这个题集后面的内容都是DP,头疼。
1.输入n个整数,输出最小的k个
Solution-1: 先排序后输出O(nlogn)//快速排序复杂度
Solution-2:把数组分为length=k, length=n-k两部分,通过比较大小来做//O(n*k)
Solution-3:用堆来处理O(n*logk)
Further:
谷歌面试题:输入是两个整数数组,他们任意两个数的和又可以组成一个数组,求这个和中前k个数怎么做?
似乎没有办法,最坏的情况只有是在
必须要对两个数组分别排序。
2.寻找和为定值的两个数
输入一个数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。
要求时间复杂度是O(N)。如果有多对数字的和等于输入的数字,输出任意一对即可。
例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。
Solution-1: 已知需要的和15,做减法得到所需差值数组14、13、11、8、4、0
2.2 寻找和为定值的两个数 | 编程之法:面试和算法心得wizardforcel.gitbooks.io我觉得这个说法有问题,题目又没说数组有序,加上排序就不止O(n)了,而是O(nlogn)
Solution-2: hash,构造hash表
分析:这类题就是排序与选择算法的问题
3.寻找和为定值的多个数
输入两个整数n和sum,从数列1,2,3.......n 中随意取几个数,使其和等于sum,要求将其中所有的可能组合列出来。
分析:不定个数就可以思考一下Tree,毫无疑问decision tree+pruning是可以奏效的,但有点花时间调代码,也不高效。
这道题同时也可视为 01背包问题的变种
不要gakki也要学会的:动态规划(DP)问题解析www.jianshu.com
不同于我们文中提到的最小张钞票凑钱,或者最大价值装背包的问题,我们现在要穷举出所有的可能组合,而不是最值组合。
感觉状态转移方程一对多就不叫状态转移方程了,类似于人工智能里面的inital state发展的问题。
inital state -> serval states:[]->...
4.最大连续子数组和
输入一个整形数组,数组里有正数也有负数。数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。 求所有子数组的和的最大值,要求时间复杂度为O(n)。
例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5
,和最大的子数组为3, 10, -4, 7, 2
, 因此输出为该子数组的和18。
这道题的难点在于,你不可能把负元素直接剔除掉,例如-4的左右分别是10和7,这个-4多半是会被计算到邻近的子数组里的。
无疑可以用DP来解了,毕竟有了最大这个最值条件,我们就可以列出正常的状态转移方程。
我们用d(i)来表示以L[i]结尾的子数组的最大和,那么有:
d(0)=1
d(1)=max{d(0),d(0)-2,-2}=1
d(2)=?
这里就要注意了,显然我们的状态转移方程走不通,不适用于L[i-1]为负数并且d(i-1)没有加入L[i-1]的情况
那么当前的状态转移方程是不对的,我们应该分写成条件分段函数

分析:为啥要用i结尾的子数组最大和来处理问题?因为我们需要的是全局子数组最大和,要简化问题,就要找到突破口,如果是子数组和,显然是不行的,因为我们没法判断是不是中间出现一个负数应该中断。
在要求f(i)必然和f(i-1)有关的情况下,可以联想到以下标作为开头或者结尾,姑且我们以下标作为结尾。
这样问题就变成了,是不是要在L[i]的基础上加入前面的子数组。
5.跳台阶问题
一个台阶总共有n 级,如果一次可以跳1 级,也可以跳2 级。
求总共有多少总跳法,并分析算法的时间复杂度。
分析:这是一道简单地DP问题
设剩余台阶数为i,一共的跳法为d(i)
那么:
d(1)=1//就只能跳一步
d(2)=2//1+1 or 2
d(3)=3//1+1+1 or 1+2 or 2+1
d(4)=5//2+2 or 1+1+1+1 or 2+1+1 or 1+2+1 or 1+1+2
d(i)=d(i-1)+d(i-2)
这似乎也可以用于求解n天后学校食堂的斐波那契汤问题...
既然有了状态转移方程,我们可以轻易得到结果
6.奇偶排序
输入一个整数数组,调整数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。要求时间复杂度为O(n)。
Solution-1: 两个指针,一个从头开始,一个从尾部开始,从头开始的遇到偶数位就停住,从尾开始的遇到奇数位就停住,如果两个指针都停住时,交换两个slot的值,继续向中间汇合,汇合之后,算法结束。
时间复杂度O(n)
这是块排partition操作的变种(invisible midium)
7.荷兰国旗问题
pass
8.矩阵相乘
请编程实现矩阵乘法,并考虑当矩阵规模较大时的优化方法
Strassen乘法应该看看这篇文章,叙述很清晰文笔很好,都可以用作讲义了
矩阵乘法Strassen算法www.jianshu.com
练习题部分:
9.不用除法运算
两个数组a[N],b[N],其中A[N]的各个元素值已知,现给b[i]赋值,b[i] = a[0]a[1]a[2]...*a[N-1]/a[i]; 要求:
- 1.不准用除法运算
- 2.除了循环计数值,a[N],b[N]外,不准再用其他任何变量(包括局部变量,全局变量等)
- 3.满足时间复杂度O(n),空间复杂度O(1)。
提示:题目要求b[i] = a[0]a[1]a[2]...a[N-1]/a[i] ,相当于求:a[0]a[1]a[2]a[3]...a[i-1]a[i+1]..a[N-1],等价于除掉当前元素a[i],其他所有元素(a[i]左边部分,和a[i]右边部分)的积。
记left[i]=∏a[k], (k=1...i-1); right=∏a[k], (k=i+1...n),根据题目描述b[i]=left[i] * right[i], 对于每一个b[i]初始化为1,left[i]和right[i]两部分可以分开两次相乘,即对于循环变量i=1...n, b[i]=left[i];b[n-i]=right[n-i], 循环完成时即可完成计算。
解析:这道题其实是考对procedural language的较深理解。
要知道不是所有语言都是有state的,比如Prolog。
既然有state,我们不妨吧b[i]看做一个state在内存中的变量,也就是一个状态(这句话可以跳过)
分成两部分,0..i-1, n..i+1,先顺序更新每个b[i]到
同理,倒序更新每个b[i]*=
大功告成。
10.找出数组中唯一重复元素
1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。 每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空间,能否设计一个算法实现?
分析:这题唯一的考点就是不用辅助存储空间
Soultion1: 暴力解法毫无疑问是轮询,比较i和其他index有没有值相同,这样是
Solution2:根据题目中特定条件,1-1000,只有唯一元素重复
int ret = sum(Array)-sum(1..1000),
Solution3:利用
对于这道题,我们需要的是唯一重复的这个元素,显然我们需要拼凑一个1..1000到异或中去,就能得到奇数个异或1个,这个数即使return值
11.找出数组中仅有的三个重复元素
一个数组里,数都是两两出现的,但是有三个数是唯一出现的,找出这三个数。
找出数组中单独出现的3个数 - weixin_34162228的博客 - CSDN博客blog.csdn.net12.找出反序的个数
给定一整型数组,若数组中某个下标值大的元素值小于某个下标值比它小的元素值,称这是一个反序。 即:数组a[]; 对于i < j 且 a[i] > a[j],则称这是一个反序。 给定一个数组,要求写一个函数,计算出这个数组里所有反序的个数。