项目介绍
本项目经过分解各大厂的常见笔面试题,追本溯源至数据结构和算法的底层实现原理,知其然知其因此然;
创建知识结构体系,方便查找,欢迎更多志同道合的朋友加入项目AlgorithmPractice,(欢迎提issue和pull request)。
Part One : 牛刀小试
这部份内容选取了几道比较简单的动态规划题目,来逐步了解什么是动态规划。java
Part Two : 抛砖引玉
这部份内容只给出了基础的解,若是有更优化的解法,请在下方留言。git
Part Three : 综合集锦
这部份内容的解法不限于动态规划,包括贪心、回溯等。github
正文开始
一、青蛙跳台阶
题目描述:在爬楼梯时,每次可向上走1阶台阶或2阶台阶,问有n阶楼 梯有多少种上楼的方式
设计思路:
状态转换方程:
statusNum[i] = statusNum[i-1] + statusNum[i-2];
注意事项:
对于常常访问的数据,能够设置缓存,方便读取。
二、最大子段和
题目描述:给定一个数组,求这个数组的连续子数组中,最大的那一段的和
代码实现:LSS,测试用例:LSSTest
设计思路:
动态规划法:
状态转换方程:
LargestSum[i] = Math.max(LargestSum[i-1] + Sequence[i], Sequence[i]);
动态规划优化法:
for(int i = 1; i < Sequence.length; i++){
sum_temp += Sequence[i];
if(sum_temp <= Sequence[i]){ //新开始
sum_temp = Sequence[i]; //sum清空
begin_temp = i; //假定的起始位置
}
if(sum < sum_temp){
sum = sum_temp; //记录最大值
begin = begin_temp; //假定的起始地址赋值给起始地址
end = i; //结束地址包括 i
}
}
分治法:
int leftValue = divide(Sequence, left, mid);
int rightValue = divide(Sequence, mid + 1, right);
int midValue = mid(Sequence, left, right);
注意事项:
三、最长公共子序列
题目描述:找出两个字符串最大匹配子串
代码实现:LCS,测试用例:LCSTest
设计思路:
状态转换方程:
num_matrix[row][column] = num_matrix[row-1][column-1]+1;
num_matrix[row][column] = num_matrix[row-1][column];
num_matrix[row][column] = num_matrix[row][column-1];
注意事项:
四、回文应用(Palindrome)
4.一、判断字符串是否属于回文
题目描述:判断给定字符串是不是回文,默认单个字符不够成回文
代码实现:
public boolean PalindromeJudge(String testString) {
if(testString == null || testString.length() == 0){
return false;
}
boolean flag = new StringBuffer(testString).reverse().toString().equals(testString);
return flag;
}
设计思路:字符串反转并匹配
注意事项:
4.二、添加一个字符构造回文
题目描述:给定一个字符串s,你能够从中添加一个字符,使得剩下的串是一个回文串,若是经过添加一个字符获得回文,则返回添加元素的位置(起始地址:1),不然返回 -1,若是自己是回文,返回中间的位置
设计思路:
注意事项:
4.三、删除一些字符构造回文
题目描述:给定一个字符串s,你能够从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢?输出须要删除的字符个数
设计思路:字符串反转,并经过LCS算法计算最大类似数,那么不类似的那些数就须要删除了。
注意事项:
4.四、查找给定字符串中最长的连续回文子串
题目描述:
代码实现:FindPalindrome,测试用例:FindPalindromeTest
4.4.一、暴力法
4.4.二、中心扩散法
4.4.三、Manacher 算法
设计思路:
4.4.一、暴力法
4.4.二、中心扩散法
4.4.三、Manacher 算法
注意事项:
五、送货最短路径
题目描述:
某物流派送员p,须要给a、b、c、d,4个快递点派送包裹, 请问派送员须要选择什么的路线,才能完成最短路程的派送。假设如图派送员的起点坐标(0,0),派送路线只能沿着图中的方格边行驶,每一个小格都是正方形,且边长为1,如p到d的距离就是4。随机输入n个派送点坐标,求输出最短派送路线值(从起点开始完成n个点派送并回到起始点的距离)。
设计思路:
贪心算法
回溯法
注意事项:
六、最佳调度问题
题目描述:设有n个任务由k个可并行工做的机器来完成,完成任务i须要时间为taskspendTime。试设计一个算法找出完成这n个任务的最佳调度,使完成所有任务的时间最先
设计思路:
注意事项:
七、最长递增子序列
题目描述:在一个给定的数值序列中,找到一个子序列,使得这个子序列元素的数值依次递增,而且这个子序列的长度尽量地大。最长递增子序列中的元素在原序列中不必定是连续的
代码实现:LIS,测试用例:LISTest
设计思路:
注意事项:
八、最大正方形
九、编辑距离
题目描述:
编辑距离指的是在两个单词之间,由其中一个单词转换为另外一个单词所须要的最少单字符编辑操做次数。在这里定义的单字符编辑操做有且仅有三种:插入(Insertion)、删除(Deletion)、替换(Substitution)
譬如,“kitten” 和 “sitting” 这两个单词,由 “kitten” 转换为 “sitting” 须要的最少单字符编辑操做有:
1.kitten → sitten (substitution of “s” for “k”)
2.sitten → sittin (substitution of “i” for “e”)
3.sittin → sitting (insertion of “g” at the end)
所以,“kitten” 和 “sitting” 这两个单词之间的编辑距离为 3 。
设计思路:
状态转换方程:
if (c1[i-1] == c2[j-1]) {
comp[i][j] = comp[i - 1][j - 1];
} else {
comp[i][j] = Math.min(Math.min(comp[i - 1][j - 1], comp[i][j - 1]), comp[i - 1][j]) + 1;
}
注意事项:
a、背包问题(backpack)
题目描述:
代码实现:backpack,测试用例:
设计思路:
注意事项:
b、合唱团(Choir)
题目描述:有 n 个学生站成一排,每一个学生有一个能力值,牛牛想从这 n个学生中按照顺序选取 ChoseNum名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 ChoseNum个学生的能力值的乘积最大,你能返回最大的乘积吗?
设计思路:
动态规划:
回溯法:
注意事项: