随笔分类 -  算法

1 2 下一页
最小的K个数:用快排的思想去解相关问题
摘要:实现快速排序算法的关键在于先在数组中选择一个数字,接下来把数组中的数字分为两部分,比选择的数字小的数字移到数组的左边,比选择的数字大的数字移到数组的右边。这个函数可以如下实现:int Partition(int data[], int length, int start, int end){ if(data == NULL || length = length) throw new std::exception("Invalid Parameters"); int index = RandomInRange(start, end); swap(&data... 阅读全文
posted @ 2014-04-06 19:16 猿人谷 阅读(651) 评论(0) 推荐(0) 编辑
八皇后问题
摘要:题目:在8×8的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后不得处在同一行、同一列或者同一对角斜线上。下图中的每个黑色格子表示一个皇后,这就是一种符合条件的摆放方法。请求出总共有多少种摆法。这就是有名的八皇后问题。解决这个问题通常需要用递归,而递归对编程能力的要求比较高。因此有不少面试官青睐这个题目,用来考察应聘者的分析复杂问题的能力以及编程的能力。由于八个皇后的任意两个不能处在同一行,那么这肯定是每一个皇后占据一行。于是我们可以定义一个数组ColumnIndex[8],数组中第i个数字表示位于第i行的皇后的列号。先把ColumnIndex的八个数字分别用0-7初始化,接 阅读全文
posted @ 2014-04-04 19:26 猿人谷 阅读(557) 评论(0) 推荐(0) 编辑
圆圈中最后剩下的数字
摘要:题目:0,1,...,n-1这n个数字排成一个圆圈,从数字0开始每次从这个圆圈里删除第m个数字。求出这个圆圈里剩下的最后一个数字。这就是有名的约瑟夫(Josephuse)环问题。可以用环形链表模拟圆圈的经典解法。分析:用模板库中的std::list来模拟一个环形链表。由于std::list本身不是一个环形结构,因此每当迭代器扫描到链表末尾的时候,要记得把迭代器移到链表的头部,这样就相当于按照顺序在一个圆圈里遍历了。这种思路的代码如下:int LastRemaining(unsigned int n, unsigned int m){ if(n numbers; for(i = 0... 阅读全文
posted @ 2014-04-04 17:17 猿人谷 阅读(529) 评论(0) 推荐(0) 编辑
不用加减乘除做加法
摘要:题目:写一个函数,求两个整数之和,要求在函数体内不得使用+、-、×、÷四则运算符号。分析:第一步:不考虑进位对每一位相加。0加0、1加1的结果都是0,0加1,1加0的结果都是1 。注意到,这和异或的结果是一样的。第二步:进位,对0加0,0加1,1加0而言,都不会产生进位,只有1加1时,会向前产生1个进位。此时我们刻意想象成是两个数先做位与运算,然后再向左移动一位。第三步:相加的过程依然是重复前面两步,知道不产生进位为止。如下是一段基于循环实现的参考代码:int Add(int num1, int num2){ int sum, carry; do{ sum = num... 阅读全文
posted @ 2014-04-04 16:47 猿人谷 阅读(381) 评论(0) 推荐(0) 编辑
和为S的两个数字VS和为s的连续正数序列
摘要:题目:输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,输出任意一对即可。例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。思路整理一下:最初我们找到数组的第一个数字和最后一个数字。首先定义两个指针,第一个指针指向数组的第一个(也就是最小的)数字,第二个指针指向数组的最后一个(也就是最大的)数字。当两个数字的和大于输入的数字时,把较大的数字往前移动;当两个数字的和小于数字时,把较小的数字往后移动;当相等时,打完收工。这样扫描的顺序是从数组的两端向数组的中间扫描。bool FindNumbersWithS 阅读全文
posted @ 2014-04-03 19:02 猿人谷 阅读(1407) 评论(0) 推荐(0) 编辑
数字在排序数组中出现的次数
摘要:题目:统计一个数字在排序数组中出现的次数。例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4.找到排序数组中的第一个K:int GetFirstK(int *data, int length, int k, int start, int end){ if(start > end) return -1; int middleIndex = start + ((end - start) >> 1); int middleData = data[middleIndex]; if(middleDat... 阅读全文
posted @ 2014-04-03 10:17 猿人谷 阅读(429) 评论(0) 推荐(0) 编辑
数组中出现次数超过一半的数字
摘要:题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。看到这道题,我们马上就会想到,要是这个数组是排序的数组就好了。如果是排序的数组,那么我们只要遍历一次就可以统计出每个数字出现的次数,这样也就能找出符合要求的数字了。题目给出的数组没有说是排好序的,因此我们需要给它排序。排序的时间复杂度是O(nlogn),再加上遍历的时间复杂度O(n),因此总的复杂度是O(nlogn)。接下来我们试着看看能不能想出更快的算法。前面思路的时间主要是花在排序上。我们可以创建一个哈希表来消除排序的时间。哈希表的键值(Key)为数组中的数字,值(Value)为该数字对应的次数。有了这个辅助的哈希表之后, 阅读全文
posted @ 2014-03-28 17:22 猿人谷 阅读(574) 评论(0) 推荐(0) 编辑
O(n)时间的排序
摘要:题目:某公司有几万名员工,请完成一个时间复杂度为O(n)的算法对该公司员工的年龄作排序,可使用O(1)的辅助空间。 题目特别强调是对一个公司的员工的年龄作排序。员工的数目虽然有几万人,但这几万员工的年龄却只有几十种可能。上班早的人一般也要等到将近二十岁才上班,一般人再晚到了六七十岁也不得不退休。 由于年龄总共只有几十种可能,我们可以很方便地统计出每一个年龄里有多少名员工。举个简单的例子,假设总共有5个员工,他们的年龄分别是25、24、26、24、25。我们统计出他们的年龄,24岁的有两个,25岁的也有两个,26岁的一个。那么我们根据年龄排序的结果就是:24、24、25、25、26,即在表示年龄 阅读全文
posted @ 2013-11-15 10:54 猿人谷 阅读(469) 评论(0) 推荐(0) 编辑
翻转句子中单词的顺序
摘要:题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样处理。例如输入“I am a student.”,则输出“student. a am I”。由于本题需要翻转句子,我们先颠倒句子中的所有字符。这时,不但翻转了句子中单词的顺序,而且单词内字符也被翻转了。我们再颠倒每个单词内的字符。由于单词内的字符被翻转两次,因此顺序仍然和输入时的顺序保持一致。还是以上面的输入为例子。翻转“I am a student.”中所有字符得到“.tneduts a ma I”,再翻转每个单词中字符的顺序得到“students. a am I” 阅读全文
posted @ 2013-11-15 10:27 猿人谷 阅读(878) 评论(0) 推荐(0) 编辑
在字符串中删除特定的字符
摘要:题目:输入两个字符串,从第一字符串中删除第二个字符串中所有的字符。例如,输入”They are students.”和”aeiou”,则删除之后的第一个字符串变成”Thy r stdnts.”。首先我们考虑如何在字符串中删除一个字符。由于字符串的内存分配方式是连续分配的。我们从字符串当中删除一个字符,需要把后面所有的字符往前移动一个字节的位置。但如果每次删除都需要移动字符串后面的字符的话,对于一个长度为n的字符串而言,删除一个字符的时间复杂度为O(n)。而对于本题而言,有可能要删除的字符的个数是n,因此该方法就删除而言的时间复杂度为O(n2)。事实上,我们并不需要在每次删除一个字符的时候都去移 阅读全文
posted @ 2013-11-12 15:41 猿人谷 阅读(2192) 评论(0) 推荐(0) 编辑
第一个只出现一次的字符
摘要:题目:在一个字符串中找到第一个只出现一次的字符。如输入abaccdeff,则输出b。看到这道题时,最直观的想法是从头开始扫描这个字符串中的每个字符。当访问到某字符时拿这个字符和后面的每个字符相比较,如果在后面没有发现重复的字符,则该字符就是只出现一次的字符。如果字符串有n个字符,每个字符可能与后面的O(n)个字符相比较,因此这种思路时间复杂度是O(n2)。我们试着去找一个更快的方法。由于题目与字符出现的次数相关,我们是不是可以统计每个字符在该字符串中出现的次数?要达到这个目的,我们需要一个数据容器来存放每个字符的出现次数。在这 个数据容器中可以根据字符来查找它出现的次数,也就是说这个容器的作用 阅读全文
posted @ 2013-11-12 15:32 猿人谷 阅读(1204) 评论(0) 推荐(0) 编辑
数对之差的最大值
摘要:题目:在数组中,数字减去它右边的数字得到一个数对之差。求所有数对之差的最大值。例如在数组{2, 4, 1, 16, 7, 5, 11, 9}中,数对之差的最大值是11,是16减去5的结果。分析:看到这个题目,很多人的第一反应是找到这个数组的最大值和最小值,然后觉得最大值减去最小值就是最终的结果。这种思路忽略了题目中很重要的一点:数对之差是一个数字减去它右边的数字。由于我们无法保证最大值一定位于数组的左边,因此这个思路不管用。于是我们接下来可以想到让每一个数字逐个减去它右边的所有数字,并通过比较得到数对之差的最大值。由于每个数字需要和它后面的O(n)个数字作减法,因此总的时间复杂度是O(n2)。 阅读全文
posted @ 2013-11-04 19:26 猿人谷 阅读(1700) 评论(0) 推荐(0) 编辑
字符串的组合
摘要:题目:输入一个字符串,输出该字符串中字符的所有组合。举个例子,如果输入abc,它的组合有a、b、c、ab、ac、bc、abc。此题也可以变换为字符串的排列。假设我们想在长度为n的字符串中求m个字符的组合。我们先从头扫描字符串的第一个字符。针对第一个字符,我们有两种选择:一是把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选取m-1个字符;二是不把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选择m个字符。这两种选择都很容易用递归实现。下面是这种思路的参考代码:void Combination(char* string){ if(string == NULL) ... 阅读全文
posted @ 2013-11-04 17:10 猿人谷 阅读(587) 评论(0) 推荐(0) 编辑
字符串的排列
摘要:题目:输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab、cba。求整个字符串的排列,可以看成两步:首先求所有可能出现在第一个位置的字符,即把第一个字符和后面所有的字符交换。下图就是分别把第一个字符a和后面b、c等字符交换的情形。第二步固定第一个字符(如图a所示),求后面所有字符的排列。这个时候我们仍把后面的所有字符分成两部分:后面字符的第一个字符,以及这个字符之后的所有字符。然后把第一个字符逐一和它后面的字符交换(如图b所示)。。。分析到这里,其实可以看出,这就是很典型的递归思路。实现代码 阅读全文
posted @ 2013-11-04 10:09 猿人谷 阅读(509) 评论(0) 推荐(0) 编辑
斐波那契额数列及青蛙跳台阶问题
摘要:题目:写一个函数,输入n,求斐波那契(Fibonacci)数列的第n项。斐波那契(Fibonacci)数列定义如下:效率很低的解法:long long Fibonacci_Solution1(unsigned int n){ if(n 2时,第一次跳的时候就有两种不同的选择:一是第一次只跳1级,此时跳法数目等于后面剩下的n-1级台阶的跳法数目,即为f(n-1);另一种选择是第一次跳2级,此时跳法数目等于后面剩下n-2级台阶的跳法数目,即为f(n-2)。因此,n级台阶的不同跳法的总数f(n)=f(n-1)+f(n-2)。分析到这里,不难看出这实际上就是斐波那契数列了。#includeusi... 阅读全文
posted @ 2013-11-03 17:01 猿人谷 阅读(7368) 评论(0) 推荐(0) 编辑
旋转数组的最小数字
摘要:题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1.实现数组的旋转见左旋转字符串。和二分查找法一样,用两个指针分别指向数组的第一个元素和最后一个元素。我们注意到旋转之后的数组实际上可以划分为两个排序的子数组,而且前面的子数组的元素都大于或者等于后面子数组的元素。我们还可以注意到最小的元素刚好是这两个子数组的分界线。我们试着用二元查找法的思路在寻找这个最小的元素。首先我们用两个指针,分别指向数组的第一个元素和最后一个元素。按照题目旋转 阅读全文
posted @ 2013-11-03 16:13 猿人谷 阅读(2387) 评论(0) 推荐(0) 编辑
扑克牌的顺子
摘要:题目:从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王可以看成任意数字。可以把5张牌看成由5个数字组成的数组。大、小王是特殊的数字,我们不妨把它们定义为0,这样就能和其他扑克牌区分开来了。接下来我们分析怎样判断5个数字是不是连续的,最直观的方法是把数组排序。值得注意的是,由于0可以当成任意数字,我们可以用0去补满数组中的空缺。如果排序之后的数组不是连续的,即相邻的两个数字相隔若干个数字,但只要我们有足够的0可以补满这两个数字的空缺,这个数组实际上还是连续的。举个例子,数组排序之后为{0,1,3,4,5},在 阅读全文
posted @ 2013-11-03 10:55 猿人谷 阅读(2276) 评论(0) 推荐(0) 编辑
左旋转字符串
摘要:来源:http://blog.csdn.net/v_july_v/article/details/6322882题目描述:定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部,如把字符串abcdef左旋转2位得到字符串cdefab。请实现字符串左旋转的函数。指针翻转法 咱们先来看个例子,如下:abc defghi,若要让abc移动至最后的过程可以是:abc defghi->def abcghi->def ghiabc 如此,我们可定义俩指针,p1指向ch[0],p2指向ch[m];一下过程循环m次,交换p1和p2所指元素,然后p1++, p2++;。第一步,交换abc 阅读全文
posted @ 2013-11-01 11:58 猿人谷 阅读(1157) 评论(0) 推荐(0) 编辑
编程小技巧
摘要:1.判断一个自然数是否是某个数的平方?(其实就是判断这个数一定是奇数相加的)由于(n+1)^2=n^2 + 2n + 1,= ...= 1 + (2*1 + 1) + (2*2 + 1) + ... + (2*n + 1)注意到这些项构成了等差数列(每项之间相差2)。所以我们可以比较 N-1, N - 1 - 3, N - 1 - 3 - 5 ... 和0的关系。如果大于0,则继续减;如果等于0,则成功退出;如果小于 0,则失败退出。复杂度为O(n^0.5)。不过方法3中利用加减法替换掉了方法1中的乘法,所以速度会更快些。例如:3^2 = 9 = 1 + 2*1+1 + 2*2+1 = 1 + 阅读全文
posted @ 2013-10-24 16:45 猿人谷 阅读(472) 评论(0) 推荐(0) 编辑
寻找数组中第二大或第二小的数值
摘要:昨天晚上参加了360校园招聘的笔试,其中最后一道笔试题就是找数组中的第二大的数。可以看出今年360笔试的试题还是不难的,想起昨晚提前把试题做完后,提前把试卷给交了,就和旁边的北大的一哥们聊天,聊最近的各种笔试、面试以及被鄙视。快到公交站时,还讨论着明天的腾讯、百度,以及晚上的去哪儿网的笔试。找工作还确实是个体力活啊!到处赶场。2013年360校园招聘题:写一个函数找出一个整数数组中,第二大的数。从一个给定的、无序的数组中,找出第二大或者第二小的数值。#include int FindSecondBiggest(int *v, int len){ if (v == NULL || len ma. 阅读全文
posted @ 2013-10-13 16:51 猿人谷 阅读(5839) 评论(11) 推荐(0) 编辑

1 2 下一页