This commit is contained in:
nonstriater
2014-05-13 09:19:55 +08:00
parent 1100bdabce
commit 16cf6be47e
13 changed files with 764 additions and 353 deletions
+5 -1
View File
@@ -117,9 +117,10 @@ http://www.chinaunix.net/old_jh/23/437639.html
*侧重经典算法的实现*
《Elements of Programming》 STL代码 快 准 狠
《Elements of Programming》 STL代码 快 准 狠 ,写出的代码可以上层次
《C interfaces and Implementation》
《The practice of programming》 Brian Kernighan和Rob Pike
《微软的梦工厂》
《Language Implementatin patterns》
@@ -199,5 +200,8 @@ http://www.cs.usfca.edu/~galles/visualization/Algorithms.html
http://leetcode.com/
http://oj.leetcode.com/
http://openjudge.cn/ POJ。这有个POJ上的ACM训练方案 http://www.java3z.com/cwbwebhome/article/article19/res041.html
http://ac.jobdu.com/index.php 九度OJ
+18 -9
View File
@@ -136,15 +136,7 @@
递减增量排序算法,对`插入排序`的改进
### 基数排序
### 总结
### 小结
常见的排序算法都是比较排序,比较排序的时间复杂度通常为 O(n^2) 或 O(nlogn)
@@ -152,6 +144,23 @@
## 3种线性排序算法
上面的算法都是基于比较的排序,时间复杂度最好也是 NlogN.
### 桶排序 bucket sort
### 计数排序 counting sort
### 基数排序 radix sort
###小结
+4
View File
@@ -66,6 +66,10 @@ BinaryTreeNode *m_pRight; // right child of node
13、设计一个算法,找出二叉树上任意两个结点的最近共同父结点。
复杂度如果是O(n2)则不得分。
+16 -11
View File
@@ -70,8 +70,6 @@ char *delete(char *source,const char *del);
题目:在一个字符串中找到第一个只出现一次的字符。如输入abaccdeff,则输出b。
分析:这道题是2006年google的一道笔试题。
@@ -87,10 +85,6 @@ hash表长度 256,字符直接作为key值
题目:匹配兄弟字符串
如果两个字符串的字符一样,但是顺序不一样,被认为是兄弟字符串,问如何在迅速匹配兄弟字符串(如,bad和adb就是兄弟字符串)。思路:判断各自素数乘积是否相等。更多方法请参见:http://blog.csdn.net/v_JULY_v/article/details/6347454。
@@ -112,20 +106,18 @@ BOOL isBrother(const char *first,const char *secd)
设计相应的数据结构和算法,尽量高效的统计一片英文文章(总单词数目)里出现的所有英文单词,按照在文章中首次出现的顺序打印输出该单词和它的出现次数。
void statistics(FILE *fd)
void statistics(FILE *fd)
字符串原地压缩
题目描述:“eeeeeaaaff" 压缩为 "e5a3f2",请编程实现。
分析
分析,主要问题在于字符串的移动
char *compress(const char *src,char *dest)
55、字符串匹配实现
字符串匹配实现
请以俩种方法,回溯与不回溯算法实现。
@@ -218,10 +210,23 @@ outputstr所指的值为123456789
char *delete_character(char *src , char target)
替换空格
实现一个函数,把每个空格替换成 "%20",如输入“we are happy”,则输出“we%20are%20happy”
寻址重复的元素
a~z包括大小写与0~9组成的N个数,用最快的方式把其中重复的元素挑出来。
hash方法。hash[128], O(N)复杂度
2.编码实现字符串转整型的函数(实现函数atoi的功能),据说是神州数码笔试题。如将字符
串 ”+123”123, ”-0123”-123, “123CS45”123, “123.45CS”123, “CS123.45”0
85.又见字符串的问题
1.给出一个函数来复制两个字符串A和B。
+26 -25
View File
@@ -14,6 +14,7 @@ int string_to_integer(char *s,int length)
请编写能直接实现int atoi(const char * pstr)函数功能的代码。 将字符串转出整数
题目:求1+2+…+n,
要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句(A?B:C)。
@@ -39,10 +40,7 @@ int factorial(n){
这是一道很基本的考查位运算的面试题。
解法1:一轮循环移位计数 (移位运算比除法运算效率要高,注意要考虑是负数的情况)
解法2:位运算
解法3:num &= num-1 巧妙之处在于,对高位没有影响
解法3:num &= num-1 巧妙之处在于,对高位没有影响。不断做 `num &= num-1` 直到num=0
@@ -56,14 +54,6 @@ int factorial(n){
1024! 末尾有多少个0?
分析:
末尾0的个数取决于2和5的个数
能被2整除的数比能被5整除的数要多得多,因此只统计被5整除的数的个数
??
编程实现:把十进制数(long型)分别以二进制和十六进制形式输出,不能使用printf系列
@@ -79,6 +69,28 @@ tmp[i]= tmp[i]>=0?tmp[i]:tmp[i]+16;
判断一个自然数是否是某个数的平方。说明:当然不能使用开方运算。
square(25) YES
square(35) NO
方法1: 从1开始遍历,显然这种方法很差
方法2: 除数跟余数比较,除数从2开始,每一轮都跟结果比较;相等就是存在这个数,不相等就把除数++;时间复杂度为(根号n)。在一个数比较大时,效率不够好。如1194877489=(34567)^2,需要从2开始,一直比较到34566,做3万多次除法和比较运算。跟方法1一样。。
方法3:二分查找 O(logn)
1024! 末尾有多少个0?
分析:
末尾0的个数取决于2和5的个数
能被2整除的数比能被5整除的数要多得多,因此只统计被5整除的数的个数
??
编程实现两个正整数的除法(和取模)
@@ -155,8 +167,8 @@ int div(const int x, const int y)
分析:这是一道广为流传的google面试题。
int one_appear_count(int n);
1. 遍历1~n,统计出现1的个数;n足够大时,效率很低
2. 分析规律
思路1. 遍历1~n,统计出现1的个数;n足够大时,效率很低
思路2. 分析规律
@@ -164,17 +176,6 @@ int one_appear_count(int n);
判断一个自然数是否是某个数的平方。说明:当然不能使用开方运算。
square(25) YES
square(35) NO
方法1: 从1开始遍历,显然这种方法很差
方法2: 除数跟余数比较,除数从2开始,每一轮都跟结果比较;相等就是存在这个数,不相等就把除数++;时间复杂度为(根号n)。在一个数比较大时,效率不够好。如1194877489=(34567)^2,需要从2开始,一直比较到34566,做3万多次除法和比较运算。跟方法1一样。。
方法3:二分查找 O(logn)
+443 -276
View File
@@ -1,6 +1,7 @@
///////// 数组 ////////////
题目:求子数组的最大和
题目:求子数组的最大和(最大字段和)
输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。
@@ -9,7 +10,53 @@
因此输出为该子数组的和18。
1. 蛮力法 fmax(i,j) 找出最大的值,3重循环 ,复杂度 0(n^3)
2.
2. maxendindhere保存当前累加的和,如果<0,就把maxendinghere清零 , max保存最终的最大和
int maxSumOfVector(int *data,int length){
int max=0;
int maxendinghere = 0;
if(data==NULL || length<=0){
return 0;
}
for(int i=0;i < length, i++){
maxendinghere+=data[i];
if(maxendinghere<0){
maxendinghere=0;
continue;
}
if(maxendinghere>max){
max=maxendinghere;
}
}
return max;
}
查找最小的k个元素(top-k)
题目:输入n个整数,输出其中最小的k个。
例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4。
topMinK(int *a,int length,int k);
topMaxK(int *a,int length, int k);
1) 全部排序 复杂度 NlogN , 数据了较大时,内存可能承受不住
2) 部分排序 维护一个大小为K的数组,由大到小排序,然后遍历所有数据,每个数据跟数组中最小元素比较,如果比最小元素大,就要插入数组了,这里还有寻找插入位置,移动数组元素的cpu消耗。复杂度是N*K
3) 堆排序 。在这的K较大时(比如这道题目:2亿个整数中求最大的100万之和),上面的算法还是有很多可以改进的地方,如采用二分查找定位插入位置,移动数组元素的计算是躲不过去了。那有没有什么数据结构即能`快速查找,还能快速移动元素`呢?最好是O(1)复杂度。
答案就是`二叉堆`。我们可以遍历总量中的每个元素来跟二叉堆中的堆顶元素比较(堆顶元素在`小根堆`中最小值,在`大根堆`中是最大值),这样在0(1)复杂度就可以完成查找操作,揭下来需要的操作就是重新调整推结构,复杂度是O(logk),因此整个操作复杂度是 O(n*logk)
`top-k 小的时候用 *大根堆* ,top-k 大得时候用 *小根堆*`
@@ -18,49 +65,306 @@
【最大/小差问题】
求相邻元素的最大差值,有无序的实数列V[N],要求求里面大小相邻的实数的差的最大值,关键是要求线性空间和线性时间
编程求解:
输入两个整数 n 和 m,从数列1,2,3.......n 中 随意取几个数,使其和等于 m ,要求将其中所有的可能组合列出来.
如 【9,-1,-11,2】 最大差值 = 2-(-11) = 13
最小差 hash合并
最大差 hash分解
桶排序
`桶排序` 比快排还快,最耗空间
编程求解:输入两个整数 n 和 m,从数列1,2,3.......n 中 随意取几个数,使其和等于 m ,要求将其中所有的可能组合列出来.
如: n=10,m=25;可能的组合有【】【】【】【】
print_sum_detials(int n , int sum)
动态规划(类似背包问题)
`动态规划`(类似背包问题)
1. 划分问题
2. 选择状态
3. 状态转移方程
4. 规划方程
输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。
要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。
例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。
int findaddends(int *data,int length,int sum,int *a,int *b); //返回0找到,返回-1没找到
分析:
数组升序排列,查找可用二分查找,时间复杂度O(logn),这样问题就变成了找其中一个加数的问题,复杂度为N*logN
巧妙解法:数组2端向中间扫描,复杂度O(N)
二维数组中的查找
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
题目:定义Fibonacci数列如下:
/ 0 n=0
f(n)= 1 n=1
/ f(n-1)+f(n-2) n=2
输入n,用最快的方法求该数列的第n项。
虽然fibonacci数列是`递归`的经典应用,但递归效率很差,会有很多重复的计算,复杂度是成指数递增的,我测试了下计算50的时候已经要300s了。
思路二:从下往上计算,复杂度O(N),一个循环就搞定
思路三: logN
查找最小的k个元素
题目:输入n个整数,输出其中最小的k个。
例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4。
print_minimums(int *a,int length ,int k);
给定一个实数数组,按序排列(从小到大),从数组从找出若干个数,使得这若干个数的和与M最为接近,描述一个算法,并给出算法的复杂度。
题目:输入一个已经按升序排序过的数组和一个数字,
在数组中查找两个数,使得它们的和正好是输入的那个数字。
要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。
例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。
一个数组是由一个递减数列左移若干位形成的,比如{4,3,2,1,6,5}
是由{6,5,4,3,2,1}左移两位形成的,在这种数组中查找某一个数。
1) 右移,二分查找。 找到最小的数,右移到第一个位置的时候,右移完成 O(N)
2) 直接二分查找
给出两个集合A和B,其中集合A={name},
集合B={age、sex、scholarship、address、...},
要求:
问题1、根据集合A中的name查询出集合B中对应的属性信息;
问题2、根据集合B中的属性信息(单个属性,如age<20等),查询出集合A中对应的name。
数组中超过出现次数超过一半的数字
题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。
分析:这是一道广为流传的面试题,包括百度、微软和Google在内的多家公司
都曾经采用过这个题目。要几十分钟的时间里很好地解答这道题,除了较好的编程能力之外,
还需要较快的反应和较强的逻辑思维能力。
+-1 ,计数法
一个int数组,里面数据无任何限制,要求求出所有这样的数a[i],
其左边的数都小于等于它,右边的数都大于等于它。
能否只用一个额外数组和少量其它空间实现。
3. 有一个函数int getNum(),每运行一次可以从一个数组V[N]里面取出一个数,N未知,当数取完的时候,函数返回NULL。现在要求写一个函数int get(),这个函数运行一次可以从V[N]里随机取出一个数,而这个数必须是符合1/N平均分布的,也就是说V[N]里面任意一个数都有1/N的机会被取出,要求空间复杂度为O(1)
题目:
找数组里面重复的一个数,一个含n个元素的整数数组至少存在一个重复数,
请编程实现,在O(n)时间内找出其中任意一个重复数。
类似问题:找出数组中唯一的重复元素
hash算法,空间要求多 (注意数组元素要位 int)
高级解法: 将问题转化为 `判断单链表中存在环`
给出洗牌的一个算法,并将洗好的牌存储在一个整形数组里
分析:扑克牌54张【2~10,J,Q,K,A,小王,大王】
1)产生随机数, 随机数 rand()%54 ,rand()每次运行都一样,要改为srand(time(NULL))
2) 遍历数组, 随机数k属于区间[i,n],然后a[i] 和 随机数 a[k] 对换
在一维坐标轴上有n个区间段,求重合区间最长的两个区间段
如【-7,21】,【4,23】,【14,100】,【54,76】
思路一:两两比较,复杂度 N^2
思路二:先排序+分而治之
奇偶分离。给定一个存放整数的数组,重新排列数组使得数组左边为奇数,右边为偶数。
要求:空间复杂度O(1),时间复杂度为O(n)
如 [4,5,2,7,5] => [5,7,5,4,2],
空间复杂度O(1),得使用 交换排序
插入排序思想
快速排序思想
1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次.
每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空间,
能否设计一个算法实现?
分析:难点在于 `不用辅助空间`。
思路一: sum(数组元素的总和)-sum(1~1000) 得到的差即为重复元素,N较大时注意总和溢出
思路二: 异或操作(位运算)
找出数组中两个只出现一次的数字
题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。
请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
分析:这是一道很新颖的关于位运算的面试题。
1) 任何一个数字异或自己都等于0,如果是只有1个只出现一次的的数字,问题就简单了。
2)
用递归的方法判断整数组a[N]是不是升序排列
递归 isAscend(n-1) && a[N-1]< a[N]
在一个int数组里查找这样的数,它大于等于左侧所有数,小于等于右侧所有数。
直观想法是用两个数组a、b。a[i]、b[i]分别保存从前到i的最大的数和从后到i的最小的数,
一个解答:这需要两次遍历,然后再遍历一次原数组,
将所有data[i]>=a[i-1]&&data[i]<=b[i]的data[i]找出即可。
给出这个解答后,面试官有要求只能用一个辅助数组,且要求少遍历一次。
一排N(最大1M)个正整数+1递增,乱序排列,第一个不是最小的,把它换成-1,
最小数为a且未知。求第一个被-1替换掉的数原来的值,并分析算法复杂度。
[4,3,5,2,7,6]
题目啥意思?
正整数序列Q中的每个元素都至少能被正整数a和b中的一个整除,现给定a和b,需要计算出Q中的前几项,例如,当a=3,b=5,N=6时,序列为3,5,6,9,10,12
(1)、设计一个函数void generate(int a,int b,int N ,int * Q)计算Q的前几项
(2)、设计测试数据来验证函数程序在各种输入下的正确性。
分析:
这个输出序列是要 递增排列
思路一: 类似对2各数组merge,取min( A[i],B[j]) .复杂度O(N)
不过这里要注意,去掉 a, b的公倍数。如 3,5 都有15可以整除
在排序数组中,找出给定数字的出现次数。比如 [1, 2, 2, 2, 3] 中2的出现次数是3次。
分析:
1. 因为是排序数组,可以使用二分查找
2. 将二分查找坚持到底,这样在最坏的情况下([2,2,2,2,2,2,2])都有0(lgn)复杂度
int binary_search_first(int *a,int length,int key);
int binary_search_lash(int *a,int length,int key);
俩个闲玩娱乐。
1.扑克牌的顺子
从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。
2-10为数字本身,A为1,J为11,Q为12,K为13,而大小王可以看成任意数字。
对这5个数(大小王看做0)
1)排序,如快排
2)统计0的个数
3)统计相邻元素空缺总数
isShunZi(int *a,int length)//5个是不是顺子
2.n个骰子的点数。
把n个骰子扔在地上,所有骰子朝上一面的点数之和为S。
输入n,打印出S的所有可能的值出现的概率。
如n=1,值【1,2,3,4,5,6】每个概率是 1/6
如n=2,值【1~12】 概率。。
把数组排成最小的数。
题目:输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个。
例如输入数组{32, 321},则输出这两个能排成的最小数字32132。
请给出解决问题的算法,并证明该算法。
分析:这是09年6月份百度的一道面试题,
从这道题我们可以看出百度对应聘者在算法方面有很高的要求。
旋转数组中的最小元素。
题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个排好序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1。
分析:这道题最直观的解法并不难。从头到尾遍历数组一次,就能找出最小的元素,
时间复杂度显然是O(N)。但这个思路没有利用输入数组的特性,我们应该能找到更好的解法。
数值的整数次方。
题目:实现函数double Power(double base, int exponent),求base的exponent次方。
不需要考虑溢出。
分析:这是一道看起来很简单的问题。可能有不少的人在看到题目后30秒写出如下的代码:
double Power(double base, int exponent)
{
double result = 1.0;
for(int i = 1; i <= exponent; ++i)
result *= base;
return result;
}
上面的代码没有考虑 exponent<0的情况。
////////////// 数列 ///////////////
输入a1,a2,...,an,b1,b2,...,bn,
在O(n)的时间,O(1)的空间将这个序列顺序改为a1,b1,a2,b2,a3,b3,...,an,bn,
且不需要移动,通过交换完成,只需一个交换空间。
@@ -87,7 +391,27 @@ print_minimums(int *a,int length ,int k);
2在下排出现了1次,3在下排出现了0次....
以此类推..
0xX0+1xX1+2xX2....+9xX9 = 10;
X0+X1+...+ = 10;
转换成多元一次方程求通解的问题。(Matlib)
一个整数数组,长度为n,将其分为m份,使各份的和相等,求m的最大值
比如{3,2,4,3,6} 可以分成{3,2,4,3,6} m=1;
{3,6}{2,4,3} m=2
{3,3}{2,4}{6} m=3 所以m的最大值为3
给出两个集合A和B,其中集合A={name},
集合B={age、sex、scholarship、address、...},
要求:
问题1、根据集合A中的name查询出集合B中对应的属性信息;
问题2、根据集合B中的属性信息(单个属性,如age<20等),查询出集合A中对应的name。
@@ -130,12 +454,6 @@ var b=[1, 2, 3, 4,5,40];
一个整数数组,长度为n,将其分为m份,使各份的和相等,求m的最大值
比如{3,2,4,3,6} 可以分成{3,2,4,3,6} m=1;
{3,6}{2,4,3} m=2
{3,3}{2,4}{6} m=3 所以m的最大值为3
n支队伍比赛,分别编号为0,1,2。。。。n-1,已知它们之间的实力对比关系,
@@ -151,11 +469,6 @@ n支队伍比赛,分别编号为0,1,2。。。。n-1,已知它们之间
一个int数组,里面数据无任何限制,要求求出所有这样的数a[i],
其左边的数都小于等于它,右边的数都大于等于它。
能否只用一个额外数组和少量其它空间实现。
一个未排序整数数组,有正负数,重新排列使负数排在正数前面,并且要求不改变原来的正负数之间相对顺序 比如: input: 1,7,-5,9,-12,15 ans: -5,-12,1,7,9,15 要求时间复杂度O(N),空间O(1) 。(此题一直没看到令我满意的答案,一般达不到题目所要求的:时间复杂度O(N),空间O(1),且保证原来正负数之间的相对位置不变)。
@@ -183,24 +496,15 @@ updated:设置一个起始点j, 一个翻转点k,一个终止点L
更多请参考此文,程序员编程艺术第二十七章:重新排列数组(不改变相对顺序&时间O(N)&空间O(1),半年未被KO)http://blog.csdn.net/v_july_v/article/details/7329314。
给定一个实数数组,按序排列(从小到大),从数组从找出若干个数,使得这若干个数的和与M最为接近,描述一个算法,并给出算法的复杂度。
1. 有无序的实数列V[N],要求求里面大小相邻的实数的差的最大值,关键是要求线性空间和线性时间
3. 有一个函数int getNum(),每运行一次可以从一个数组V[N]里面取出一个数,N未知,当数取完的时候,函数返回NULL。现在要求写一个函数int get(),这个函数运行一次可以从V[N]里随机取出一个数,而这个数必须是符合1/N平均分布的,也就是说V[N]里面任意一个数都有1/N的机会被取出,要求空间复杂度为O(1)
21、搜狗笔试题:一个长度为n的数组a[0],a[1],...,a[n-1]。现在更新数组的名个元素,即a[0]变为a[1]到a[n-1]的积,a[1]变为a[0]和a[2]到a[n-1]的积,...,a[n-1]为a[0]到a[n-2]的积(就是除掉当前元素,其他所有元素的积)。程序要求:具有线性复杂度,且不能使用除法运算符。
搜狗笔试题:一个长度为n的数组a[0],a[1],...,a[n-1]。现在更新数组的名个元素,即a[0]变为a[1]到a[n-1]的积,a[1]变为a[0]和a[2]到a[n-1]的积,...,a[n-1]为a[0]到a[n-2]的积(就是除掉当前元素,其他所有元素的积)。程序要求:具有线性复杂度,且不能使用除法运算符。
思路:left[i]标示着a[i]之前的乘积,right[i]标示着a[i]之后的乘积,但不申请空间,那么a[i]=left[i]*right[i] 。不过,left的计算从左往右扫的时候得出,right是从右往左扫得出。因为就是当中某个元素a[i]的左边所有元素与右边所有元素的乘积,就这么简单。所以计算a[i]=left[i]*right[i]时,直接出结果。
22、后2012年4月6日的腾讯暑期实习生招聘笔试中,出了一道与上述21题类似的题,原题大致如下:
后2012年4月6日的腾讯暑期实习生招聘笔试中,出了一道与上述21题类似的题,原题大致如下:
两个数组a[N],b[N],其中A[N]的各个元素值已知,现给b[i]赋值,b[i] = a[0]*a[1]*a[2]...*a[N-1]/a[i];
要求:
@@ -234,7 +538,6 @@ b[0] *= a[1];
94.微软笔试题
求随机数构成的数组中找到长度大于=3的最长的等差数列9 d- x' W) w9 ?" o3 b0 R
输出等差数列由小到大:
如果没有符合条件的就输出
@@ -246,65 +549,6 @@ b[0] *= a[1];
93.在一个int数组里查找这样的数,它大于等于左侧所有数,小于等于右侧所有数。
直观想法是用两个数组a、b。a[i]、b[i]分别保存从前到i的最大的数和从后到i的最小的数,
一个解答:这需要两次遍历,然后再遍历一次原数组,
将所有data[i]>=a[i-1]&&data[i]<=b[i]的data[i]找出即可。
给出这个解答后,面试官有要求只能用一个辅助数组,且要求少遍历一次。
第19题:
题目:定义Fibonacci数列如下:
/ 0 n=0
f(n)= 1 n=1
/ f(n-1)+f(n-2) n=2
输入n,用最快的方法求该数列的第n项。
分析:在很多C语言教科书中讲到递归函数的时候,都会用Fibonacci作为例子。
因此很多程序员对这道题的递归解法非常熟悉,但....呵呵,你知道的。。
寻址重复的元素
1.a~z包括大小写与0~9组成的N个数
用最快的方式把其中重复的元素挑出来。
74.数组中超过出现次数超过一半的数字
题目:数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。
分析:这是一道广为流传的面试题,包括百度、微软和Google在内的多家公司
都曾经采用过这个题目。要几十分钟的时间里很好地解答这道题,除了较好的编程能力之外,
还需要较快的反应和较强的逻辑思维能力。
+-1 ,计数法
题目大意如下:
一排N(最大1M)个正整数+1递增,乱序排列,第一个不是最小的,把它换成-1,
最小数为a且未知求第一个被-1替换掉的数原来的值,并分析算法复杂度。
4.给出洗牌的一个算法,并将洗好的牌存储在一个整形数组里。
在一维坐标轴上有n个区间段,求重合区间最长的两个区间段。
16、正整数序列Q中的每个元素都至少能被正整数a和b中的一个整除,现给定a和b,需要计算出Q中的前几项,例如,当a=3,b=5,N=6时,序列为3,5,6,9,10,12
(1)、设计一个函数void generate(int a,int b,int N ,int * Q)计算Q的前几项
(2)、设计测试数据来验证函数程序在各种输入下的正确性。
57、求最大重叠区间大小
@@ -319,148 +563,48 @@ f(n)= 1 n=1
给定一个存放整数的数组,重新排列数组使得数组左边为奇数,右边为偶数。
要求:空间复杂度O(1),时间复杂度为O(n)。
48、找出数组中唯一的重复元素
1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次.
每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空间,
能否设计一个算法实现?
2.用递归的方法判断整数组a[N]是不是升序排列
给定一个存放整数的数组,重新排列数组使得数组左边为奇数,右边为偶数。
要求:空间复杂度O(1),时间复杂度为O(n)。
35.
求一个矩阵中最大的二维矩阵(元素和最大).如:
1 2 0 3 4
2 3 4 5 1
1 1 5 3 0
中最大的是:
4 5
5 3
要求:(1)写出算法;(2)分析时间复杂度;(3)用C写出关键代码
1.对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右)某一个元素也加一,
现给出一正数矩阵,判断其是否能够由一个全零矩阵经过上述运算得到。
38、顺时针打印矩阵
题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
例如:如果输入如下矩阵:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
则依次打印出数字1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10。
分析:包括Autodesk、EMC在内的多家公司在面试或者笔试里采用过这道题。
一个数组是由一个递减数列左移若干位形成的,比如{4,3,2,1,6,5}
是由{6,5,4,3,2,1}左移两位形成的,在这种数组中查找某一个数。
俩个闲玩娱乐。
1.扑克牌的顺子
从扑克牌中随机抽5张牌,判断是不是一个顺子,即这5张牌是不是连续的。
2-10为数字本身,A为1,J为11,Q为12,K为13,而大小王可以看成任意数字。
2.n个骰子的点数。
把n个骰子扔在地上,所有骰子朝上一面的点数之和为S。
输入n,打印出S的所有可能的值出现的概率。
68.把数组排成最小的数。
题目:输入一个正整数数组,将它们连接起来排成一个数,输出能排出的所有数字中最小的一个。
例如输入数组{32, 321},则输出这两个能排成的最小数字32132。
请给出解决问题的算法,并证明该算法。
分析:这是09年6月份百度的一道面试题,
从这道题我们可以看出百度对应聘者在算法方面有很高的要求。
69.旋转数组中的最小元素。
题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个排好序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3, 4, 5, 1, 2}为{1, 2, 3, 4, 5}的一个旋转,该数组的最小值为1。
分析:这道题最直观的解法并不难。从头到尾遍历数组一次,就能找出最小的元素,
时间复杂度显然是O(N)。但这个思路没有利用输入数组的特性,我们应该能找到更好的解法。
71.数值的整数次方。
题目:实现函数double Power(double base, int exponent),求base的exponent次方。
不需要考虑溢出。
分析:这是一道看起来很简单的问题。可能有不少的人在看到题目后30秒写出如下的代码:
double Power(double base, int exponent)
{
double result = 1.0;
for(int i = 1; i <= exponent; ++i)
result *= base;
return result;
}
61.找出数组中两个只出现一次的数字
题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。
请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
分析:这是一道很新颖的关于位运算的面试题。
64. 寻找丑数。
题目:我们把只包含因子2、3和5的数称作丑数(Ugly Number)。
例如6、8都是丑数,但14不是,因为它包含因子7。习惯上我们把1当做是第一个丑数。
求按从小到大的顺序的第1500个丑数。
分析:这是一道在网络上广为流传的面试题,据说google曾经采用过这道题。
65.输出1到最大的N位数
题目:输入数字n,按顺序输出从1最大的n位10进制数。
比如输入3,则输出1、2、3一直到最大的3位数即999。
输出1到最大的N位数
题目:输入数字n,按顺序输出从1最大的n位10进制数。比如输入3,则输出1、2、3一直到最大的3位数即999。
分析:这是一道很有意思的题目。看起来很简单,其实里面却有不少的玄机。
输入4,输出: 1,2,3,。。9999
输入5,输出: 1,2,3,4,...99999
玄机一: 整数溢出
一个有序数列,序列中的每一个值都能够被2或者3或者5所整除,1是这个序列的第一个元素。求第1500个值是多少?
和为n连续正数序列。
题目:输入一个正数n,输出所有和为n连续正数序列。
例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以输出3个连续序列1-5、4-6和7-8。
print_continuous_sequence_sum(int n)
思路一:枚举法。从1开始一直加到等于n,再从2开始。。一直到 n/2+1,在每一轮,都要逐步比较。复杂度O(N^2)
思路二: a[small,big] sum[small,big]>N small往前移动,否则,big往前移动。 O(N)复杂度搞定
一个整数数列,元素取值可能是1~N(N是一个较大的正整数)中的任意一个数,相同数值不会重复出现。
设计一个算法,找出数列中符合条件的数对的个数,满足数对中两数的和等于N+1。
复杂度最好是O(n),如果是O(n2)则不得分。
分析:列出所有的数对,如输入15,输出【1,14】【2,13】【3,12】。。。
int print_sequence_sum(int n)
一个有序数列,序列中的每一个值都能够被2或者3或者5所整除,1是这个序列的第一个元素。求第1500个值是多少?(与下面的寻找丑数是一个意思)
1,2,3,4,5,6,8,9,10,12,14,15,16,...
@@ -477,83 +621,106 @@ unsigned long value_in_sequence(int index)
和为n连续正数序列。
题目:输入一个正数n,输出所有和为n连续正数序列。
寻找丑数
题目:我们把只包含因子2、3和5的数称作丑数(Ugly Number)。
例如6、8都是丑数,但14不是,因为它包含因子7。习惯上我们把1当做是第一个丑数。
求按从小到大的顺序的第1500个丑数。
例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以输出3个连续序列1-5、4-6和7-8。
分析:这是一道在网络上广为流传的面试题,据说google曾经采用过这道题。
这里的因子应该不包含本身,因此这个序列应该是这样:
1,2,3,4,5,6,8,9,10,12,15,16,18,20,28....
54.调整数组顺序使奇数位于偶数前面。
调整数组顺序使奇数位于偶数前面。
题目:输入一个整数数组,调整数组中数字的顺序,使得所有奇数位于数组的前半部分,
所有偶数位于数组的后半部分。要求时间复杂度为O(n)。
47.创新工场:
求一个数组的最长递减子序列 比如{9,4,3,2,5,4,3,2}的最长递减子序列为{9,5,4,3,2}
思路:两边向中间扫描,如果第一个指针是偶数,第二个指针是奇数,就交换;如果第一个是偶数,第二个也偶数,第二个指针向前移;反之,第一个指针向后移
void reorder(int *data, int length);
有一个整数数组,请求出两两之差绝对值最小的值,
记住,只要得出最小值即可,不需要求出是哪两个数。
求一个数组的最长递减子序列。 比如{9,4,3,2,5,4,3,2}的最长递减子序列为{9,5,4,3,2}
`动态规划`
有一个整数数组,请求出两两之差绝对值最小的值,记住,只要得出最小值即可,不需要求出是哪两个数。
如 [-1, 3, 5, 9] 绝对值最小的是2(5-3)
最短区间问题
如果是有重复元素,那最小值就是0了
解题思路: 可以将这个问题转化为 ”求最大字段和“ 问题。。。
12、一个整数数列,元素取值可能是0~65535中的任意一个数,相同数值不会重复出现。0是例外,可以反复出现。
请设计一个算法,当你从该数列中随意选取5个数值,判断这5个数值是否连续相邻。
一个整数数列,元素取值可能是0~65535中的任意一个数,相同数值不会重复出现。0是例外,可以反复出现。请设计一个算法,当你从该数列中随意选取5个数值,判断这5个数值是否连续相邻。
注意:
- 5个数值允许是乱序的。比如: 8 7 5 0 6
- 0可以通配任意数值。比如:8 7 5 0 6 中的0可以通配成9或者4
- 0可以多次出现。
- 复杂度如果是O(n2)则不得分。
一个整数数列,元素取值可能是1~N(N是一个较大的正整数)中的任意一个数,相同数值不会重复出现。
设计一个算法,找出数列中符合条件的数对的个数,满足数对中两数的和等于N+1。
复杂度最好是O(n),如果是O(n2)则不得分。
这个问题跟”扑克牌顺子“判断问题一样,通过比较0的个数和相邻数字之间间隔总和来判断所有数是否连续。
56、一个含n个元素的整数数组至少存在一个重复数,
请编程实现,在O(n)时间内找出其中任意一个重复数。
在排序数组中,找出给定数字的出现次数
比如 [1, 2, 2, 2, 3] 中2的出现次数是3次。
分析:
1. 因为是排序数组,可以使用二分查找
2. 将二分查找坚持到底,这样在最坏的情况下([2,2,2,2,2,2,2])都有0(lgn)复杂度
int binary_search_first(int *a,int length,int key);
int binary_search_lash(int *a,int length,int key);
53、最长递增子序列
最长递增子序列
题目描述:设L=<a1,a2,…,an>是n个不同的实数的序列,L的递增子序列是这样一个子序列
Lin=<aK1,ak2,…,akm>,其中k1<k2<…<km且aK1<ak2<…<akm。
Lin=< aK1,ak2,…,akm >,其中k1< k2<…< km且aK1< ak2<…< akm。
求最大的m值。
如【5,6,7,3,2,8】 最长子序列 【5,6,7,8】
`动态规划`
/////////////////////// 矩阵 /////////////////////////////////
求一个矩阵中最大的二维矩阵(元素和最大).如:
1 2 0 3 4
2 3 4 5 1
1 1 5 3 0
中最大的是:
4 5
5 3
要求:(1)写出算法;(2)分析时间复杂度;(3)用C写出关键代码
对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右)某一个元素也加一,
现给出一正数矩阵,判断其是否能够由一个全零矩阵经过上述运算得到。
顺时针打印矩阵
题目:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字。
例如:如果输入如下矩阵:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
则依次打印出数字1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10。
分析:包括Autodesk、EMC在内的多家公司在面试或者笔试里采用过这道题。
+47
View File
@@ -0,0 +1,47 @@
#include "stdio.h"
void generate(int a,int b,int N ,int * Q){
int p=1,q=1;
int tmpA,tmpB;
for (int i = 0; i < N; ++i)
{
tmpA = a*p;
tmpB = b*q;
if (tmpA>tmpB)
{
Q[i]=tmpB;
q++;
}
else if(tmpA<tmpB)
{
Q[i]=tmpA;
p++;
}
else{// ==
Q[i]=tmpA;
p++;
q++;
}
}
}
int main(int argc, char const *argv[])
{
int a[10];
generate(3,5,10,a);
for (int i = 0; i < 10; ++i)
{
printf(" %d \n", a[i]);
}
return 0;
}
+47
View File
@@ -0,0 +1,47 @@
#include "stdio.h"
void print_continuous_sequence_sum(int n){// n=1,2
int small=1;
int big=2;
int sum = small+big;
while(small<big && big<=n/2+1){
if (sum==n)
{
printf("%d ,%d\n",small,big);
}
while(sum>n){
sum-=small;
small++;
if (sum==n)
{
printf("%d, %d\n",small,big);
}
}
big++;
sum+=big;
}
}
int main(int argc, char const *argv[])
{
print_continuous_sequence_sum(115);
return 0;
}
+55
View File
@@ -0,0 +1,55 @@
#include "stdio.h"
void reorder(int *data, int length){
int i=0;
int j=length-1;
while(i<j){
if (!isEvenNum(data[i]) )
{
i++;
continue;
}
if (isEvenNum(data[j]) )
{
j--;
continue;
}
//交换
int tmp ;
tmp = data[i];
data[i] = data[j];
data[j] = tmp;
}
}
int isEvenNum(int n){
return (n&1) == 0;
}
int main(int argc, char const *argv[])
{
int a[]= {5,2,7,8,9,34,21,6};
reorder(a,8);
for (int i = 0; i < 8; ++i)
{
printf(" %d ", a[i]);
}
return 0;
}
@@ -0,0 +1,57 @@
#include "stdio.h"
#include "time.h"
int fibonacci(int n){
int result[2] = {0,1};
if (n<2)
{
return result[n];
}
return fibonacci(n-1)+fibonacci(n-2);
}
// 循环
int fibonacci2(int n){
int result[2] = {0,1};
if ( n<2 )
{
return result[n];
}
int fibOne=0;
int fibTwo=1;
int fibN;
for (int i = 2; i < n; ++i)
{
fibN = fibOne + fibTwo;
fibOne = fibTwo;
fibTwo = fibN;
}
return fibN;
}
int main(){
int start,end;
long result;
start = clock();
result=fibonacci2(40);
end = clock();
printf("%ld %.6fs",result,(double)(end-start)/CLOCKS_PER_SEC);
return 0;
}
+3 -2
View File
@@ -162,7 +162,8 @@ char first_appear_only_once(const char *source){
// 最大对称子串的长度
int max_symmetrical_char_length(const char *scr){
int max_symmetrical_length=1;
return 0;
@@ -243,7 +244,7 @@ char *strcpy(const char *src,char *dest){
// aabcd & bcad , abc&bca
BOOL isBrother(const char *first,const char *secd){
return YES;
}
+41 -29
View File
@@ -14,7 +14,7 @@
6. 分布处理之 Hadoop/Mapreduce
### 海量日志处理,提取某日访问百度次数最多的那个IP(或top-K IP)
### 海量日志处理,提取某日访问百度次数最多的那个IP
分析
@@ -53,19 +53,15 @@ unsigned count[N],这个N=2^32=4G个IP地址 sizeof(count) = 4*N = 16G内存,
###top-K 找出最大的k个数
hashmap + 堆
分析: hashmap统计+二叉堆
100w个数中找出最大的100个数。
类似问题:
寻找热门查询,300万个查询字符串中统计最热门的10个查询。
有一个文件中保存了2亿个整数,每个整数都以' '分隔。求最大的100万个整数之和。
有一千万条短信,有重复,以文本文件的形式保存,一行一条,有重复。请用5分钟时间,找出重复出现最多的前10条。
一个文件中包含了1亿个随机整数,如何快速的找到最大(小)的100万个数字?(时间复杂度:O(n lg k))
分析:100W个数里面是否有重复
@@ -78,33 +74,54 @@ hashmap + 堆
这里给个最简单hash函数,`字符串到int类型的哈希`
int hash_function(const char *p)
{
int value = 0;
while (*p != '\0')
{
value = value * 31 + *p++;
if (value > HASHLEN)
value = value % HASHLEN;
}
return value;
}
这个hash函数要确保 不同的字符串 hash出不同的一个 整数。
有一千万条短信,有重复,以文本文件的形式保存,一行一条,有重复。
请用5分钟时间,找出重复出现最多的前10条。
寻找热门查询,300万个查询字符串中统计最热门的10个查询
### 文件中的内容排序并去重复
类似的题目有:
大量的URL字符串(电话号码),如何从中去除重复的,优化时间空间复杂度
linux中的几个命令:
sort 将文件内容排序
uniq 检查和删除文件内容中重复出现的行列
comm 比较2个已经排序的文件
对于较大文件 G级别的文件
split -b 把大文件分割成小文件
然后用 sort 分别排序
sort -m 合并结果
然后在 uniq 命令去重
文件中的内容排序并去重复
一个文件中包含了1亿个随机整数,如何快速的找到最大(小)的100万个数字?(时间复杂度:O(n lg k))
分析: 堆排序
3.2 在O(n lg k)时间内,将k个排序表合并成一个排序表,n为所有有序表中元素个数。
### 在O(n lg k)时间内,将k个排序表合并成一个排序表,n为所有有序表中元素个数。
【解析】取前100 万个整数,构造成了一棵数组方式存储的具有小顶堆,然后接着依次取下一个整数,如果它大于最小元素亦即堆顶元素,则将其赋予堆顶元素,然后用Heapify调整整个堆,如此下去,则最后留在堆中的100万个整数即为所求 100万个数字。该方法可大大节约内存。
搜索中的智能提示(如 "中国" ,"zhongguo",考虑拼音)
### 搜索中的智能提示(如 "中国" ,"zhongguo",考虑拼音)
把2万个汉字排序,弄成一个超长的字符串
用Int16索引汉字的所有拼音
@@ -114,11 +131,6 @@ Int64 建立汉字和拼音的关联--汉字有多音字,需要把多个拼音
3.大量的URL字符串,如何从中去除重复的,优化时间空间复杂度
2.一个文件,内含一千万行字符串,每个字符串在1K以内,
要求找出所有相反的串对,如abc和cba。
@@ -130,7 +142,7 @@ Int64 建立汉字和拼音的关联--汉字有多音字,需要把多个拼音
2.给出一个文件,里面包含两个字段{url、size},
给出一个文件,里面包含两个字段{url、size},
即url为网址,size为对应网址访问的次数,
要求:
问题1、利用Linux Shell命令或自己设计算法,
@@ -141,7 +153,7 @@ Int64 建立汉字和拼音的关联--汉字有多音字,需要把多个拼音
3.有10个文件,每个文件1G,
有10个文件,每个文件1G,
每个文件的每一行都存放的是用户的query,每个文件的query都可能重复。
要求按照query的频度排序.
+2
View File
@@ -135,6 +135,8 @@ struct ListNode
该题以及它的变体经常出现在各大公司的面试、笔试题中。
从尾到头打印链表