算法面试题(1)

时间:2022-01-28 09:40:49

1.比较两个字符串如果不等返回True?


答案:

Java代码 算法面试题(1)
  1. package com.test.kaoshi;  
  2.   
  3. public class StringDemo  
  4.   
  5.     private static String "abc" 
  6.     private static String "abcg" 
  7.   
  8.     public static boolean equalString()  
  9.         if (a.equals(b))  
  10.             return false 
  11.         else  
  12.               
  13.             return true 
  14.          
  15.      
  16.     public static void main(String[] args)  
  17.         StringDemo  sd new StringDemo();  
  18.         System.out.println("主要考察返回Boolean变量和字符串比较使用的方法?+sd.equalString());  
  19.      
  20.  

package com.test.kaoshi;

public class StringDemo {

private static String a = "abc";
private static String b = "abcg";

public static boolean equalString() {
if (a.equals(b)) {
return false;
} else {

return true;
}
}
public static void main(String[] args) {
StringDemo sd = new StringDemo();
System.out.println("主要考察返回Boolean变量和字符串比较使用的方法?+sd.equalString());
}
}






2.随机产生20个字符并且排序?

答案:



Java代码 算法面试题(1)



  1. package com.test.kaoshi;
      

  2.   

  3. import java.util.HashSet;
      

  4. import java.util.Iterator;
      

  5. import java.util.Random;
      

  6. import java.util.Set;
      

  7. import java.util.TreeSet;
      

  8.   

  9. public class RadomDemo {
      

  10.   


  11.     public Set getChar(){
      


  12.         
      


  13.         Set numberSet01 new HashSet();
      


  14.         Random rdm new Random();
      


  15.         char ch;
      


  16.         while(numberSet01.size()<20){ 
      


  17.            int rdGet Math.abs(rdm.nextInt())%26+97;//产生97到122的随机数a-z值
      


  18.             ch=(char)rdGet;
      


  19.             numberSet01.add(ch);
      


  20.             //Set中是不能放进重复的值的,当它有20个时,就满足你的条件了 
      


  21.         
      


  22.           return numberSet01;
      


  23.         }
      


  24.     public static void main(String[] args) {
      


  25.         RadomDemo rd new RadomDemo();
      


  26.         Set numberSet01=rd.getChar();
      


  27.         
      


  28.         Set numberSet new TreeSet(); 
      


  29.         numberSet.addAll(numberSet01);
      


  30.         for(Iterator it=numberSet01.iterator();it.hasNext();){ 
      


  31.             System.out.print(it.next()); 
      


  32.             
      


  33.         System.out.println();
      


  34.         for(Iterator it=numberSet.iterator();it.hasNext();){ 
      


  35.             System.out.print(it.next()); 
      


  36.             
      


  37.     }
      

  38.  




package com.test.kaoshi;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;

public class RadomDemo {

public Set getChar(){

Set numberSet01 = new HashSet();
Random rdm = new Random();
char ch;
while(numberSet01.size()<20){
int rdGet = Math.abs(rdm.nextInt())%26+97;//产生97到122的随机数a-z值
ch=(char)rdGet;
numberSet01.add(ch);
//Set中是不能放进重复的值的,当它有20个时,就满足你的条件了
}
return numberSet01;
}
public static void main(String[] args) {
RadomDemo rd = new RadomDemo();
Set numberSet01=rd.getChar();

Set numberSet = new TreeSet();
numberSet.addAll(numberSet01);
for(Iterator it=numberSet01.iterator();it.hasNext();){
System.out.print(it.next());
}
System.out.println();
for(Iterator it=numberSet.iterator();it.hasNext();){
System.out.print(it.next());
}
}
}



3.50个人围成一圈数到三和三的倍数时出圈,问剩下的人是谁?在原来的位置是多少?


答案:



Java代码 算法面试题(1)



  1. package com.test.kaoshi;
      

  2.   

  3. import java.util.Iterator;
      

  4. import java.util.LinkedList;
      

  5.   

  6. public class YouXi {
      


  7.     public static int removeNM(int n, int m) {
      


  8.         LinkedList ll new LinkedList();
      


  9.         for (int 0n; i++)
      


  10.             ll.add(new Integer(i 1));
      


  11.         int removed -1;
      


  12.         while (ll.size() 1{
      


  13.             removed (removed m) ll.size();
      


  14.             ll.remove(removed--);
      


  15.         }
      


  16.         return ((Integer) ll.get(0)).intValue();
      


  17.     }
      

  18.   


  19.     public static void main(String[] args) {
      


  20.         System.out.println(removeNM(503));
      


  21.     }
      

  22.  



. 时针分针重合几次
表面上有60个小格,每小格代表一分钟,
时针每分钟走1/12小格,分针每分钟走1小格,从第一次重合到第二次重合分针比时针多走一圈即60小格,所以
60/(1-1/12)=720/11
每隔720/11分才重合一次(而并不是每小时重合一次)

1440里有22个720/11,如果说算上0点和24点,那也是重合23次而已,但我觉得0点应该算到前一天的24点头上,所以每一天循环下来重合22次啊


2. 找出字符串的最长不重复子串,输出长度
建一个256个单元的数组,每一个单元代表一个字符,数组中保存上次该字符上次出现的位置;
依次读入字符串,同时维护数组的值;
如果遇到冲突了,就返回冲突字符中保存的位置,继续第二步。也可以用hashmap保存已经出现的字符和字符的位置

3. 说是有一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出
现的前十个词。
先用哈希,统计每个词出现的次数,然后在用在N个数中找出前K大个数的方法找出出现
次数最多的前10个词。

4. 如题3,但是车次文件特别大,没有办法一次读入内存。
1) 直接排序,写文件时,同时写入字符串及其出现
次数。
2)
可以用哈希,比如先根据字符串的第一个字符将字符串换分为多个区域,每个区域的字符串写到一个文件内,然后再用哈希+堆统计每个区域内前10个频率最高的字符串,最后求出所有字符串中前10个频率最高的字符串。


5. 有一个整数n,将n分解成若干个整数之和,问如何分解能使这些数的乘积最大,输出这个乘积m。例如:n=12
(1)分解为1+1+1+…+1,12个1, m=1*1*1……*1=1
(2)分解为2+2+…+2,6个2, m=64
(3)分解为3+3+3+3,4个3, m=81
(4)大于等于4时分解时只能分解为2和3,且2最多两个
f(n) = 3*f(n-3) n>4
f(4) = 2*2
f(3) = 3
f(2) = 2分解为4+4+4,3个4, m=64

6. 求数组n中出现次数超过一半的数
把数组分成[n/2]组,则至少有一组包含重复的数,因为如果无重复数,则最多只有出现次数等于一半的数。算法如下:
k<-n;
while k>3 do
把数组分成[k/2]组;
for i=1 to [k/2] do
    if
组内2个数相同,则任取一个数留下;
    else
2个数同时扔掉;
k<-剩下的数
if k=3
    then
任取2个数进行比较;
     
if 两个数不同,则2个数都扔掉
      
else 任取一个数
    if k=2 or 1
then 任取一数

7. A文件中最多有n个正整数,而且每个数均小于n,n <=10的七次方。不会出现重复的数。
要求对A文件中的数进行排序,可用内存为1M,磁盘可用空间足够。
不要把任何问题都往很复杂的算法上靠,最直接最简单的解决问题才是工程师应有的素质,
题目给的很有分寸:n个数,都小于n,两两不同,1M=10^6byte=10^7bit的内存,n
<10^7
思路:
把1M内存看作是一个长度为10^7的位数组,每一位都初始化为0
从头扫描n个数,如果碰到i,就把位数组的第i个位置置为1,


1M内存有点少, (1M = 8M bits), 可以代表8M整数,现在n
<=10的七次方,你可以读2遍文件,就可以完成排序了。第一次排n
<8M得数, 第2遍排 8M <n
<10的七次方的数。


8. 有10亿个杂乱无章的数,怎样最快地求出其中前1000大的数。
1) 建一个1000个数的堆,复杂度为N*(log1000)=10N
2)
1.用每一个BIT标识一个整数的存在与否,这样一个字节可以标识8个整数的存在与否,对于所有32位的整数,需要512Mb,所以开辟一个512Mb的字符数组A,初始全0

  
2.依次读取每个数n,将A[n>>3]设置为A[n>>3]|(1<<n%8),相当于将每个数的对应位设置为1

  
3.在A中,从大到小读取1000个值为1的数,就是最大的1000个数了。
这样读文件就只需要1遍,在不考虑内存开销的情况下,应该是速度最快的方法了。

9. 一棵树节点1, 2, 3, ... , n. 怎样实现:
先进行O(n)预处理,然后任给两个节点,用O(1)判断它们的父子关系
dfs一遍,记录每个结点的开始访问时间Si和结束访问时间Ei
对于两个节点i,j,若区间[Si,Ei]包含[Sj,Ej],则i是j的祖先。给每个节点哈夫曼编码也行,但只适合一般的二叉树,而实际问题未必是Binary的,所以编码有局限性


10. 给定一个二叉树,求其中N(N>=2)个节点的最近公共祖先节点。每个节点只有左右孩
子指
针,没有父指针。
后序递归给每个节点打分,每个节点的分数=左分数+右分数+k,如果某孩子是给定节点则+1
最深的得分为N的节点就是所求吧,细节上应该不用递归结束就可以得到这个节点

11. 如何打印如下的螺旋队列:
21 22 。。。。
20 7 8 9 10
19 6 1 2 11
18 5 4 3 12
17 16 15 14 13

#include <stdio.h>
#define max(a,b) ((a)<(b)?(b):(a))
#define abs(a) ((a)>0?(a):-(a))
int foo(int x, int y)
{
int t = max(abs(x), abs(y));
int u = t + t;
int v = u - 1;
v = v * v + u;
if (x == -t)
    v += u + t -
y;
else if (y == -t)
    v += 3 * u +
x - t;
else if (y == t )
    v += t -
x;
else
         
v += y - t;
return v;
}
int main()
{
int x, y;
for (y=-2;y<=2;y++)
{
    for
(x=-2;x<=2;x++)
     
printf("%5d", foo(x, y));
   
printf("\n");
}
return 0;
}
第 0 层规定为中间的那个 1,第 1 层为 2 到 9,第 2 层为 10 到 25,……好像看出一点名堂来了?注意到
1、9、25、……不就是平方数吗?而且是连续奇数(1、3、5、……)的平方数。这些数还跟层数相关,推算一下就可以知道第 t
层之内一共有 (2t-1)^2 个数,因而第 t 层会从 [(2t-1)^2] + 1 开始继续往外螺旋。给定坐标
(x,y),如何知道该点处于第几层?so easy,层数 t = max(|x|,|y|)。

知道了层数,接下来就好办多了,这时我们就知道所求的那点一定在第 t
层这个圈上,顺着往下数就是了。要注意的就是螺旋队列数值增长方向和坐标轴正方向并不一定相同。我们可以分成四种情况——上、下、左、右——或者——东、南、西、北,分别处于四条边上来分析。


东|右:x == t,队列增长方向和 y 轴一致,正东方向(y = 0)数值为 (2t-1)^2 + t,所以 v =
(2t-1)^2 + t + y

南|下:y == t,队列增长方向和 x 轴相反,正南方向(x = 0)数值为 (2t-1)^2 + 3t,所以 v =
(2t-1)^2 + 3t - x

西|左:x == -t,队列增长方向和 y 轴相反,正西方向(y = 0)数值为 (2t-1)^2 + 5t,所以 v =
(2t-1)^2 + 5t - y

北|上:y == -t,队列增长方向和 x 轴一致,正北方向(x = 0)数值为 (2t-1)^2 + 7t,所以 v =
(2t-1)^2 + 7t + x

12. 一个整数,知道位数,如何判断它是否能被3整除,不可以使用除法和模运算
首先 3x=2^n+1时 仅当 n 为奇数才可能 因为2^n = 3x + (-1)^n;所以该问题就转化为了
找到最后一个为1的位a,看看向前的一个1(b)和这个位的距离,如果为偶数的距离则不能整除,如果是奇数,去除b之后的位继续判断


13.
seq=[a,b,...,z,aa,ab,...,az,ba,bb...,bz,...za,zb,...,zz,aaa...],求[a-z]+(从a到z任意字符组成的字符串)s在seq的位置,即排在第几

本质就是26进制。



大家都知道,看一个数是否能被2整除只需要看它的个位能否被2整除即可。可是你想过为什么吗?这是因为10能被2整除,因此一个数10a+b能被2整除当且仅当b能被2整除。大家也知道,看一个数能否被3整除只需要看各位数之和是否能被3整除。这又是为什么呢?答案或多或少有些类似:因为10^n-1总能被3整除。2345可以写成2*(999+1)
+ 3*(99+1) + 4*(9+1) + 5,展开就是2*999+3*99+4*9 +
2+3+4+5。前面带了数字9的项肯定都能被3整除了,于是要看2345能否被3整除就只需要看2+3+4+5能否被3整除了。当然,这种技巧只能在10进制下使用,不过类似的结论可以推广到任意进制。

    
注意到36是4的整数倍,而ZZZ...ZZ除以7总是得555...55。也就是说,判断一个36进制数能否被4整除只需要看它的个位,而一个36进制数能被7整除当且仅当各位数之和能被7整除。如果一个数同时能被4和7整除,那么这个数就一定能被28整除。于是问题转化为,有多少个连续句子满足各位数字和是7的倍数,同时最后一个数是4的倍数。这样,我们得到了一个O(n)的算法:用P[i]表示前若干个句子除以7的余数为i有多少种情况,扫描整篇文章并不断更新P数组。当某句话的最后一个字能被4整除时,假设以这句话结尾的前缀和除以7余x,则将此时P[x]的值累加到最后的输出结果中(两个前缀的数字和除以7余数相同,则较长的前缀多出来的部分一定整除7)。

    
上述算法是我出这道题的本意,但比赛后我见到了其它各种各样新奇的算法。比如有人注意到36^n mod
28总是等于8,利用这个性质也可以构造出类似的线性算法来。还有人用动态规划(或者说递推)完美地解决了这个问题。我们用f[i,j]表示以句子i结束,除以28余数为j的文本片段有多少个;处理下一句话时我们需要对每一个不同的j进行一次扫描,把f[i-1,j]加进对应的f[i,j']中。最后输出所有的f[i,0]的总和即可。这个动态规划可以用滚动数组,因此它的空间同前面的算法一样也是常数的。

    
如果你完全不知道我在说什么,你可以看看和进位制同余相关的文章。另外,我之前还曾出过一道很类似的题(VOJ1090),你可以对比着看一看。


 


 



有一个整数n,写一个函数f(n),返回0到n之间出现的"1"的个数。比如f(13)=6,现在f(1)=1,问有哪些n能满足f(n)=n?


例如:f(13)=6, 因为1,2,3,4,5,6,7,8,9,10,11,12,13.数数1的个数,正好是6.

public class Test {

public int n = 2;

public int count = 0;

public void BigestNumber(int num) {

for (int i = 1; i <= num; i++) {
int m = 0;

int j = i;
while (j > 0) {
m = j % 10;

if (m == 1)
     
count++;
if (j > 0)
      j = j /
10;

}

}

System.out.println("f(" + num + ")=" + count);


}

public static void main(String args[]) {
Test t = new Test();
long begin = System.currentTimeMillis();
t.BigestNumber(10000000);
long end = System.currentTimeMillis();
System.out.println("总时间" + (end-begin)/1000 + "秒");
}
}


结果:
f(10000000)=7000001
总时间5秒