From 81e6ec3f533d1f8626c3d5995436c6a8931601a2 Mon Sep 17 00:00:00 2001 From: ranwenjie Date: Mon, 15 Nov 2021 01:44:14 +0800 Subject: [PATCH] update dp --- 8 Algorithms Analysis/动态规划.md | 27 +++++++++++++-- 9 Algorithms Job Interview/1.1 字符串-查找.md | 33 ++++++++++++++++++- .../5.2 数列-nsum问题.md | 3 +- 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/8 Algorithms Analysis/动态规划.md b/8 Algorithms Analysis/动态规划.md index eaeef85..a034b8b 100644 --- a/8 Algorithms Analysis/动态规划.md +++ b/8 Algorithms Analysis/动态规划.md @@ -25,7 +25,7 @@ DP通常基于一个递推公式及一个(或多个)初始状态,当前子问 * 凑零钱问题 * 股票问题 [代码参考这里](https://github.com/nonstriater/deep-in-java/blob/master/src/main/java/com/nonstriater/deepinjava/algo/list/stock/BestChance.java) * 打家劫舍问题 : num[i] 代表第i个房子中的现金数目,从房子中取钱的最大数目,约束是相邻房子的钱不能同时取出 -* 接雨水问题 : +* 接雨水问题 :num[i]表示柱子高度,计算下雨之后能接多少雨水 * 青蛙跳阶问题: 一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 10 级的台阶总共有多少种跳法。 * 最小编辑距离 * 最长递增子序列 (LIS Longest Increasing Subsequence),如`【5,6,7,3,2,8】` 最长子序列 `【5,6,7,8】`, 输出4 @@ -56,8 +56,6 @@ DP通常基于一个递推公式及一个(或多个)初始状态,当前子问 - - ### DP VS 分治法 与[分治法](分治算法.md)不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。 @@ -105,6 +103,29 @@ for 状态1 in 状态1的所有取值: ```Java +//递归解法,处理重叠子问题, 使用 dp[amount+1] 备忘录 + int coinChange2(int[] coins, int amount) { + int[] dp = new int[amount + 1]; + + // 数组大小为 amount + 1,初始值也为 amount + 1 + // 为啥 dp 数组初始化为 amount + 1 呢,因为凑成 amount 金额的硬币数最多只可能等于 amount(全用 1 元面值的硬币),所以初始化为 amount + 1 就相当于初始化为正无穷 + Arrays.fill(dp, amount + 1); + + // base case + dp[0] = 0; + // 外层 for 循环在遍历所有状态的所有取值 + for (int i = 0; i < dp.length; i++) { + // 内层 for 循环在求所有选择的最小值 + for (int coin : coins) { + // 子问题无解,跳过 + if (i - coin < 0) { + continue; + } + dp[i] = Math.min(dp[i], 1 + dp[i - coin]); + } + } + return (dp[amount] == amount + 1) ? -1 : dp[amount]; + } ``` diff --git a/9 Algorithms Job Interview/1.1 字符串-查找.md b/9 Algorithms Job Interview/1.1 字符串-查找.md index c7b6aa9..18e9d22 100644 --- a/9 Algorithms Job Interview/1.1 字符串-查找.md +++ b/9 Algorithms Job Interview/1.1 字符串-查找.md @@ -193,7 +193,7 @@ int longest_common_subsequence(const char *s1,const char *s2, char *common){ ``` -## 对称子字符串的最大长度 +## 对称子字符串的最大长度 (最长回文子串) 题目:输入一个字符串,输出该字符串中对称的子字符串的最大长度。比如输入字符串“google”,由于该字符串里最长的对称子字符串是“goog”,因此输出4。 @@ -215,6 +215,37 @@ int max_symmetrical_char_length(const char *scr){ ``` +```Java + public String longestPalindrome(String s) { + String res = ""; + for (int i = 0; i < s.length(); i++) { + // 以 s[i] 为中心的最长回文子串 + String s1 = palindrome(s, i, i); + + // 以 s[i] 和 s[i+1] 为中心的最长回文子串 + String s2 = palindrome(s, i, i + 1); + + // res = longest(res, s1, s2) + res = res.length() > s1.length() ? res : s1; + res = res.length() > s2.length() ? res : s2; + } + return res; + } + + //实现一个函数来寻找最长回文串 + String palindrome(String s, int l, int r) { + // 防止索引越界 + while (l >= 0 && r < s.length() + && s.charAt(l) == s.charAt(r)) { + // 向两边展开 + l--; r++; + } + // 返回以 s[l] 和 s[r] 为中心的最长回文串 + return s.substring(l + 1, r); + } +``` + + ## 子串匹配的个数 diff --git a/9 Algorithms Job Interview/5.2 数列-nsum问题.md b/9 Algorithms Job Interview/5.2 数列-nsum问题.md index 895026f..d76c014 100644 --- a/9 Algorithms Job Interview/5.2 数列-nsum问题.md +++ b/9 Algorithms Job Interview/5.2 数列-nsum问题.md @@ -81,7 +81,6 @@ int findaddends(int *data,int length,int sum,int *a,int *b); - ## 求子数组的最大和(最大字段和) 输入一个整形数组,数组里有正数也有负数。 @@ -91,7 +90,7 @@ int findaddends(int *data,int length,int sum,int *a,int *b); 例如输入的数组为`1, -2, 3, 10, -4, 7, 2, -5` ,和最大的子数组为`3, 10, -4, 7, 2` ,因此输出为该子数组的和18。 1. 蛮力法 fmax(i,j) 找出最大的值,3重循环 ,复杂度 0(n^3) -2. maxendindhere保存当前累加的和,如果<0,就把maxendinghere清零 , max保存最终的最大和; 如果都是负数 +2. `动态规划` maxendindhere保存当前累加的和,如果<0, 就把maxendinghere清零 , max保存最终的最大和; 如果都是负数 ``` int maxSumOfVector(int *data,int length){