面试算法的复习和整理,争取每天一个算法[常更长新]

  一哥们去一著名跨国大大大的公司去面试。在很多项目经验,设计,架构,前台,后端都考察个遍后...私以为快要拿到Offer的时候... 不信的事情发生了。
考官出了两道大二时候经常考的算法题。用惯了IDE的他居然一时蒙掉了,提笔多次却无从落笔。悲剧之余,只得铩羽而归...
  为了不和这哥们一样,我觉得好好复习复习算法相关的问题,争取每天一个算法题,以题促进。对于我个人的解决方案肯定有部分是比较粗陋的,希望各位大牛不吝赐教,留下各位的算法。当然我觉得各位在看我的算法之前自己动手写写应该也是有提高的,最好是用记事本写,然后直接Copy到IDE中测试,看看离开了Intelligence还能不能直接Run的起来...
  1: 经典的冒泡排序
  简述:给出一组乱序数组 如: int[] a = new int[10]{4,3,5,1,6,2,9,10,8,7};
  要求:写出f(n), 使得乱序数组按序排列。    
View Code
1 public static void RunSnippet()
2 {
3 int[] a = new int[] {4, 3, 5, 1, 6, 2, 9, 10, 8, 7};
4 //int[] a = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
5 //int[] a = new int[] {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
6   int temp = 0, count = 0;
7 for (int i = 1; i < a.Length; i++)
8 {
9 for (int j = 0; j < a.Length - i; j++)
10 {
11 if (a[j] > a[j + 1])
12 {
13 temp = a[j + 1];
14 a[j + 1] = a[j];
15 a[j] = temp;
16 count += 1;
17 }
18 }
19 }
20 //for (int i = 0; i < a.Length; i++)
21 //{
22 // for (int j = i + 1; j < a.Length; j++)
23 // {
24 // if (a[j] < a[i])
25 // {
26 // temp = a[i];
27 // a[i] = a[j];
28 // a[j] = temp;
29 // count += 1;
30 // }
31 // }
32 //}
33   for (int i = 0; i < a.Length; i++)
34 {
35 Console.WriteLine(a[i].ToString());
36 }
37 Console.WriteLine("Count:" + count);
38 Console.ReadLine();
39 }
  解析:面试最常见的排序之一,按顺序将每一个值和后面的所有值作一次比较,符合要求(如 a[0] > a[1])则a[0]与a[1]交换,否则不变;这样一轮下来总能保证最小的冒到最上面(给出的算法一为最大的沉到最下面,两种算法稍有不同,自己体会下)。N(数组的Length-1)轮过后,对每一个数字都进行了调换,于是排序成功。

  扩展:待补充...
  2: 面试题:菲薄那题数列
  简述:给出一数字序列 {1,1,2,3,5,8...}
  要求:写出f(n), 计算第N位数字的值。
View Code
1 public static void RunSnippet()
2 {
3 int a = 1,b = 1,total = 0;
4 int n;
5 n = int.Parse(Console.ReadLine());
6 n = n -2;
7 if(n<=0)
8 {
9 total = 1;
10 }
11 else
12 {
13 for(int i =0;i<n;i++)
14 {
15 total = a+b;
16 a=b;
17 b=total;
18 }
19 }
20 Console.WriteLine(total);
21 }
  解析:同样常见的面试题,有题可知,每个数字均为前两个数字之和,由于规定不能用递归,所以用循环的方法就是只能由小做到大。设定两个变量存储前两位值,每次循环为这两个变量重新赋值,直到循环到需求的次数为止。
  扩展:待补充...
  3: 面试题:任意插入排序
  简述:给出两数字序列 int[] a = new int[]{1,2,3,4,7,8,9,10}; 和 int[] b = new int[]{2,5,6,8};
  要求:写出f(n), 把b中的数字按顺序插入到a中,为了简便,默认a,b中数字已经排序。   
View Code
1 public static void RunSnippet()
2 {
3 int[] a = new int[]{1,2,3,4,7,8,9,10};
4 int[] b = new int[]{2,5,6,8};
5 int z= 0;
6 int[] result = new int[a.Length+b.Length];
7 for(int i = 0;i<a.Length;i++)
8 {
9 for(int j=0;j<b.Length;j++)
10 {
11 if(a[i]>b[j])
12 {
13 result[z]=b[j];
14 b[j] = int.MaxValue;
15 z+=1;
16 }
17 }
18 result[z] = a[i];
19 z+=1;
20 }
21 for(int i = 0;i<result.Length;i++)
22 {
23 Console.WriteLine(result[i]);
24 }
25 }
 
   解析:典型的插值,我稍加改变,本来是插入一个数,我改成了插入一个数组。实现原理就是new新的数组result,然后按顺序把a中元素和b中的每个元素比较,符合要求的(a[i]>b[j])家,先插入b[j]到result数组,在插入a[i],否则直接插入a[i]。这里设置b[j]为int.MaxValue是为了不对b中元素重复操作。我想肯定有更好的算法,希望大家不吝赐教。

  扩展:待补充...
  4: 直接插入排序
  简述:给出一数字序列 int[] a = new int[10]{4,3,5,1,6,2,9,10,8,7};
  要求:写出f(n),使得无序数组按序排列。
 
View Code
1 public static void RunSnippet()
2 {
3 int[] a = new int[] { 4, 3, 5, 1, 6, 2, 9, 10, 8, 7 };
4 //int[] a = new int[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
5 //int[] a = new int[] {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
6 int count = 0,temp = 0;
7 for (int i = 1; i < a.Length; i++)
8 {
9 temp = a[i];
10 int j = i - 1;
11 while (j >= 0 && a[j] > temp)
12 {
13 a[j + 1] = a[j];
14 j--;
15 count += 1;
16 }
17 a[j + 1] = temp;
18 }
19 // temp = 0;
20 // for (int i = 1; i < a.Length; i++)
21 // {
22 // for (int j = 0; j < i; j++)
23 // {
24 // if (a[i] < a[j])
25 // {
26 // for (int k = i; k > j; k--)
27 // {
28 // temp = a[k];
29 // a[k] = a[k - 1];
30 // a[k - 1] = temp;
31 // count += 1;
32 // }
33 // break;
34 // }
35 // }
36 // }
37 for (int i = 0; i < a.Length; i++)
38 {
39 Console.WriteLine(a[i].ToString());
40 }
41 Console.WriteLine("Count:" + count);
42 Console.ReadLine();
43 }


  解析:直接插值排序,将a[n]和a[0]比较,如果符合要求(如:a[n]<a[0]),移动数字到a[0]前,否则继续比较a[n]和a[1],共需要比较n-1次。因为每次和前面比较的数列必定是已经排好序的,所以只要命中一次符合条件的判断,就可以退出比较循环了,两种算法是一样的,写法不同,可以在VS中跟踪一下。
  扩展:待补充...

  5: 希尔排序
  简述:给出一数字序列 int[] a = new int[10]{4,3,5,1,6,2,9,10,8,7};
  要求:写出f(n),使得无序数组按序排列。
  

View Code
1 public static void RunSnippet()
2 {
3 int[] a = new int[] { 4, 3, 5, 1, 6, 2, 9, 10, 8, 7 };
4 //int[] a = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
5 //int[] a = new int[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };
6 int count = 0, temp = 0;
7 for (int h = a.Length/3; h > 0; h /= 2)
8 {
9 for (int i = h; i < a.Length; i+=h)
10 {
11 for (int j = 0; j < i; j += h)
12 {
13 if (a[i] < a[j])
14 {
15 for (int k = i; k > j; k -= h)
16 {
17 temp = a[k];
18 a[k] = a[k - h];
19 a[k - h] = temp;
20 count += 1;
21 }
22 break;
23 }
24 }
25 }
26 }
27
28 for (int i = 0; i < a.Length; i++)
29 {
30 Console.WriteLine(a[i]);
31 }
32 Console.WriteLine("Count:" + count);
33 Console.ReadLine();
34 }

  解析:直接排序的升级版,开始会去一个跳跃值,使得每个数字不用和相邻的比较交换,而是根据跳跃值得到不同间隔值的若干组数,并在组内采用直接插入排序,最后的一组的间隔为1。如题中,总长度为10,跳跃值为3,分成的组为{a[3],a[6],a[9]},{a[*]},间隔分别为3和1。 
  扩展:选取不同的跳跃值对排序的性能有比较大的影响,怎么选取合适的跳跃值是个问题...

  6: 面试题:数列替换
  简述:给出两字串序列 string[] a = new string[]{"a","b","c","d","e","f","a","b","c","d","e"}; string[] b = new string[]{"b","c","d"};
  要求:写出f(n), 把a串中同b的字串队列用空格代替。
  

View Code
1 public static void RunSnippet()
2 {
3 string[] a = new string[]{"a","b","c","d","e","f","a","b","c","d","e"};
4 string[] b = new string[]{"b","c","d"};
5 int temp;
6 for(int i=0;i<a.Length;i++)
7 {
8 temp = i;
9 for(int j=0;j<b.Length;j++)
10 {
11 if(a[i]==a[j])
12 {
13 i+=1;
14 }
15 else
16 {
17 i=temp;
18 break;
19 }
20 if(j==b.Length-1)
21 {
22 for(int k=0;k<b.Length;k++)
23 {
24 a[i]="";
25 i-=1;
26 }
27 i=temp+b.Length;
28 }
29 }
30 }
31 for(int i=0;i<a.Length;i++)
32 {
33 Console.WriteLine(a[i].ToString());
34 }
35 }

  解析:不知道算不算是最简陋的算法了,基本不用解释也是一看就明白了。思路是将a中的字符轮序与b中的字符比较,碰到第一个不同就退出,如果都相同倒过来全部置为空,跳过b的长度继续比较。
  扩展:待补充...

  7: 面试题:求小于某数字的所有素数
  简述:输入一个正整数。求出所有素数
  要求:写出f(n), 列出所有仅能被2和自身整除的数。
  

View Code
1 public static void RunSnippet()
2 {
3 int a = Convert.ToInt32(Console.ReadLine());
4 if(a<3)
5 {
6 Console.WriteLine(2);
7 return;
8 }
9 IList<int> su = new List<int>();
10 for(int i=3;i<a;i+=2)
11 {
12 int j=0;
13 for(j=2;j<=i/2;j++)
14 {
15 if(i%j==0)
16 {
17 break;
18 }
19 }
20 if(j>i/2)
21 {
22 su.Add(i);
23 }
24 }
25 foreach(int i in su)
26 {
27 Console.Write(i.ToString()+';');
28 }
29 }

  解析:比较简单的题目,按照题意遍历就可以了,不过个人感觉效率不行,大于100W速度就不行了。
  扩展:待补充...

  8: 面试题:求两个数字的最大公约数
  简述:输入两个正整数,求出最大公约数。
  要求:写出f(n),求出最大的能被两个数整除的数。  
View Code
1 public static void RunSnippet()
2 {
3 int a= Convert.ToInt32(Console.ReadLine());
4 int b= Convert.ToInt32(Console.ReadLine());
5 int temp = 1;
6 while(temp != 0)
7 {
8 if(a>b)
9 {
10 temp=a%b;
11 a=b;
12 b=temp;
13 }
14 else
15 {
16 temp=b%a;
17 b=temp;
18 }
19 }
20 Console.WriteLine(a);
21 }

  解析:根据最大公约数的定义来编程,大数整除小数取余;然后小数作为大数,余数作为小数继续上一步骤,直到余数为0,则最后那个小数为最大公约数。
  扩展:待补充...

  9: 面试题:产生一个int数组,长度为100,并向其中随机插入1-100,并且不能重复。
  简述:生成一个数组,长度为100,用1-100的随机数填充此数组,数组中的数字不能重复。
  要求:写出f(n),完成需求,不能使用hashtable等集合类型。 

View Code
1 public static void RunSnippet()
2 {
3 int[] all = new int[100];
4 Random ro = new Random();
5 int newInt = 0;
6 for (int i = 0; i < 100; i++)
7 {
8 bool insert = false;
9 while (insert == false)
10 {
11 insert = true;
12 newInt = ro.Next(1, 101);
13 for (int j = 0; j < i; j++)
14 {
15 if (all[j] == newInt)
16 {
17 insert = false;
18 break;
19 }
20 }
21 }
22 all[i] = newInt;
23 }
24
25 for (int i = 0; i < 100; i++)
26 {
27 Console.WriteLine(all[i]);
28 }
29 Console.ReadLine();
30 }

  解析:题目不难,就是取随机数插入数组,每次取得随机数都和数组中现有数字比较,如果已经存在那就重新取随机数,当然我提供的算法只是简单的提供一下思路,还有很大的优化空间。
  扩展:待补充...

posted on 2011-04-16 21:21  Dennis.Yang  阅读(1979)  评论(5编辑  收藏  举报