动态规划(Dynamic Programming)
动态规划的常规步骤
相关概念
无后效性
有后效性
练习-找零钱
此题在leetcode动态规划的方法讲解:
提交的代码:
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount+1];
Arrays.fill(dp, amount+1);
dp[0] = 0;
for(int i=1; i<=amount; i++){
for(int j=0; j<coins.length; j++){
if(coins[j]<=i){
dp[i] = Math.min(dp[i], dp[i-coins[j]]+1);
}
}
}
return dp[amount] > amount ? -1 : dp[amount];
}
}
做这题时发现leetcode上的Integer.MAX_VALUE是个负数
练习-最长递增子序列
class Solution {
public int lengthOfLIS(int[] nums) {
int[] dp = new int[nums.length];
Arrays.fill(dp, 1);
dp[0] = 1;
int ans = 1;
for(int i=1; i<nums.length; i++){
for(int j=0; j<i; j++){
if(nums[i] > nums[j]){
dp[i] = Math.max(dp[i], dp[j]+1);
}
}
ans = Math.max(ans, dp[i]);
}
return ans;
}
}
这道题目的核心就是dp[i]存的是以nums[i]为结尾的最长递增子序列。
练习-最长公共子序列(二维动态规划)
先看看leetcode上的讲解
提交的代码
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int[][] dp = new int[text1.length()+1][text2.length()+1];
for(int i=1; i<=text1.length(); i++){
for(int j=1; j<=text2.length(); j++){
char c1 = text1.charAt(i-1);
char c2 = text2.charAt(j-1);
if(c1 == c2){
dp[i][j] = dp[i-1][j-1] + 1;
}
else{
dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
}
}
}
return dp[text1.length()][text2.length()];
}
}
这道题经典二维动态规划的题目值得一背,最长公共子串同样可以用二维动态规划求解。
练习-0-1背包问题
leetcode上找不到题目,所以记住思路即可,0-1背包问题也是很经典的二维动态规划问题。
串(Sequence)
前缀、真前缀、后缀、真后缀
串匹配算法
蛮力法
KMP
蛮力与KMP对比
KMP-next表的使用
KMP-核心原理
KMP-真前缀后缀的最大公共子串长度
KMP-得到next
KMP-得到next数组的代码设计
虽然不是java代码,但相信也是看得懂的
有了next数组,相信后面文本串和模式串匹配的主代码完全不是问题了
KMP-不足之处
KMP-优化思路
说白了就是,不断根据next表向前找,找到一个与当前pi指向元素不一样的元素为止,避免根据next数组得到一个与原本相同的元素,进行不必要的比较
KMP-性能分析
略显尴尬的是,暴力法其实也就O(nm)左右的时间复杂度,暴力法耗时也不长。