今天面试的一道算法题,当时解得不太好,各种被面试官问住,回家在地铁上想到了如下的解法。
问题:请设计算法查找出一个字符串中重复出现最多的字符以及次数
一开始我是这么写的,也是最普通的写法,两个循环,设两个临时变量就输出结果
static private void method_derectLoop(String s) { Char[] c_s = s.ToCharArray(); Int32 i_Count = 0; Char c_Char = ' '; //i_hasCounted是数过的相同字符数的总的个数, for (Int32 i = 0; i < c_s.Length; i ++) { //i_tempCount是一个临时的变量,包含了c_s[i]在字符串中出现的个数 Int32 i_tempCount = 0; for (Int32 j = i; j < c_s.Length; j++) { if (c_s[i] == c_s[j]) { i_tempCount++; } } if (i_tempCount > i_Count) { i_Count = i_tempCount; c_Char = c_s[i]; } } Console.WriteLine("Count="+i_Count); Console.WriteLine("Char=" + c_Char); //Console.WriteLine(new String(c_s)); }
这个解法面试官不是很满意,因为已经计算过次数的元素还是需要继续遍历一遍,这个时候我说那建立一个数组去存储已经计算过次数的元素,但是这种方法会多一个循环,在元素过多的情况下效率也不高,当时确实没有什么好的解法,就只好作罢,此时镜头一转,来到了地铁10号线上一个低头思考的同学身上,我终于想到了一个办法可以跳过已经计算的元素,那就是每计算一次交换一下元素的位置,计算完一次之后将所有相同的元素放在数组的开头,然后跳过这些元素从下一个开始,代码如下
static private void method_skipLoop(String s) { Char[] c_s = s.ToCharArray(); Int32 i_Count = 0; Int32 i_hasCounted = 0; Int32 i_loopCount = 0; Char c_Char = ' '; //i_hasCounted是数过的字符数的总的个数,这些字符已经在数组的开头,可以直接跳过 for (Int32 i = 0; i < c_s.Length; i = i_hasCounted) { //i_tempCount是一个临时的变量,包含了c_s[i]在字符串中出现的个数 Int32 i_tempCount = 0; for (Int32 j = i; j < c_s.Length; j++) { i_loopCount++; if (c_s[i] == c_s[j]) { //如果出现相同,不是同一个元素或者不是相邻元素,交换位置 i_tempCount++; if (i != j && j != i + i_tempCount - 1) { Char c_tempChar = c_s[i + i_tempCount - 1]; c_s[i + i_tempCount - 1] = c_s[j]; c_s[j] = c_tempChar; } } } if (i_tempCount > i_Count) { i_Count = i_tempCount; c_Char = c_s[i]; } i_hasCounted += i_tempCount; } Console.WriteLine("Count="+i_Count); Console.WriteLine("Char=" + c_Char); //Console.WriteLine(new String(c_s)); }
第二种方法在s的比较短的时候执行的时间是会慢的,以为这个时候方法一和方法二的循环次数差不多,而方法二还需要多执行其他的操作。
不过当s的长度大于1000时区别就会出现(我的机器比较挫),当s十分长的时候方法二的优势就会显现出来了。
我们科以简单来分析一下方法二循环执行的次数,假设每个字母在s中出现的概率是相同的,有k个不同字母,s的长度为n
那么第一次循环遍历的元素为:n
第二次为:(1-1/k)n
第三次为:(1-2/k)n
...
最后一次为n/k
然后将这些加起来有
遍历次数=(((1+k-1)(k-1))\2))*n=((k(k-1))/2)*n
而k<=26,所以((k(k-1))/2)可以近似为一个常数c,
所以方法二的遍历次数=cn
时间复杂度为O(n)
而方法一的时间复杂度是n^2。
后来也上网查了一下其他的解法,正在研究中...