动态规划之子序列问题 大多是需要二维动态规划的
遍历顺序大多是从上往下 从左往右,特别的回文子串和最长回文子序列,是从下往上。
目录
300.最⻓递增⼦序列
class Solution {
public int lengthOfLIS(int[] nums) {
if(nums.length == 0) return 0;
int[] dp = new int[nums.length];
int res = 0;
Arrays.fill(dp, 1);// 默认是1
for(int i = 0; i < nums.length; i++) {
for(int j = 0; j < i; j++) {
if(nums[j] < nums[i]) dp[i] = Math.max(dp[i], dp[j] + 1);
}
res = Math.max(res, dp[i]);
}
return res;
}
}
674. 最⻓连续递增序列
贪心
class Solution {
public int findLengthOfLCIS(int[] nums) {
int res = 1, max = 1;
for (int i = 1; i < nums.length; i++) {
if (nums[i] > nums[i - 1]) {
res++;
} else {
res = 1;
}
max = Math.max(max, res);
}
return max;
}
}
基于本题贪心的思路,可以联想到LeetCode原题: 122. 买卖股票的最佳时机 II,贪心的思路为:因为交易次数不受限,我们可以把所有的上坡全部收集到,然后求和,其结果一定是利益最大化
作者:ju-ren-zhang
链接:https://leetcode-cn.com/problems/longest-continuous-increasing-subsequence/solution/tu-biao-si-lu-kan-bu-dong-ni-da-wo-ji-ba-7fr7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
动态规划:
class Solution {
public int findLengthOfLCIS(int[] nums) {
int[] dp = new int[nums.length];
Arrays.fill(dp, 1);
int res = 1;
for (int i = 1; i < nums.length; i++) {
if (nums[i] > nums[i - 1]) {
dp[i] = dp[i - 1] + 1;
}
res = Math.max(res, dp[i]);
}
return res;
}
}
718. 最⻓重复⼦数组
class Solution {
public int findLength(int[] nums1, int[] nums2) {
int n = nums1.length;
int m = nums2.length;
int[][] dp = new int[n + 1][m + 1]; // dp[i][j]表示A的前i项与B的前j项的最长重复子数组长度
int ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
if (nums1[i - 1] == nums2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
ans = Math.max(ans,dp[i][j]);
}
}
}
return ans;
}
}
1143.最⻓公共⼦序列
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int n1 = text1.length(),n2 = text2.length();
int[][] dp = new int[n1+1][n2+1];
for (int i = 1; i <= n1; i++) {
for (int j = 1; j <= n2; j++) {
char c1 = text1.charAt(i-1);
char c2 = text2.charAt(j-1);
dp[i][j] = c1==c2 ? dp[i-1][j-1]+1 : Math.max(dp[i-1][j],dp[i][j-1]);
}
}
return dp[n1][n2];
}
}
53. 最⼤⼦序和
class Solution {
public int maxSubArray(int[] nums) {
// if(nums==null||nums.length==0)return null;
if(nums.length==1)return nums[0];
int pre = nums[0];
int max = Integer.MIN_VALUE;
max = Math.max(max,pre);
for (int i = 1; i < nums.length; i++) {
pre = Math.max(nums[i],nums[i]+pre);
// i依次增加 pre会依次变成以对应位置结尾的子序列和的最大值
// max存储 所有位置序列和的最大值
max = Math.max(max,pre);
}
return max;
}
}
392.判断⼦序列
这道题⽬算是编辑距离的⼊⻔题⽬(毕竟这⾥只是涉及到减法),也是动态规划解决的经典题型。
可以用双指针来做
class Solution {
public boolean isSubsequence(String s, String t) {
int slen = s.length(), tlen = t.length();
if(slen>tlen) return false;
if(slen==0)return true;
int sptr = 0, tptr = 0;
while(tptr<tlen){
if(t.charAt(tptr)==s.charAt(sptr) && (++sptr==slen)) {
return true;
}
tptr++;
}
return false;
}
}
动态规划也可
115.不同的⼦序列
class Solution {
public int numDistinct(String s, String t) {
int[][] dp = new int[t.length() + 1][s.length() + 1];
for (int j = 0; j < s.length() + 1; j++) dp[0][j] = 1;
for (int i = 1; i < t.length() + 1; i++) {
for (int j = 1; j < s.length() + 1; j++) {
if (t.charAt(i - 1) == s.charAt(j - 1)) dp[i][j] = dp[i - 1][j - 1] + dp[i][j - 1];
else dp[i][j] = dp[i][j - 1];
}
}
return dp[t.length()][s.length()];
}
}
583. 两个字符串的删除操作
用 最长公共子序列即可
class Solution {
public int minDistance(String word1, String word2) {
int m = word1.length(), n = word2.length();
int[][] dp = new int[m + 1][n + 1];
for (int i = 1; i <= m; i++) {
char c1 = word1.charAt(i - 1);
for (int j = 1; j <= n; j++) {
char c2 = word2.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]);
}
}
}
int lcs = dp[m][n];
return m - lcs + n - lcs;
}
}
72. 编辑距离
public int minDistance(String word1, String word2) {
int m = word1.length();
int n = word2.length();
int[][] dp = new int[m + 1][n + 1];
// 初始化
for (int i = 1; i <= m; i++) {
dp[i][0] = i;
}
for (int j = 1; j <= n; j++) {
dp[0][j] = j;
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
// 因为dp数组有效位从1开始
// 所以当前遍历到的字符串的位置为i-1 | j-1
if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = Math.min(Math.min(dp[i - 1][j - 1], dp[i][j - 1]), dp[i - 1][j]) + 1;
}
}
}
return dp[m][n];
}
647. 回⽂⼦串
516.最⻓回⽂⼦序列
class Solution {
public int longestPalindromeSubseq(String s) {
int n = s.length();
int[][] dp = new int[n][n];// 初始化为0 表示 s[i:j]最长回文子串长度为0
for (int i = n - 1; i >= 0; i--) {
dp[i][i] = 1;
char c1 = s.charAt(i);
for (int j = i + 1; j < n; j++) {
char c2 = s.charAt(j);
if (c1 == c2) {
dp[i][j] = dp[i + 1][j - 1] + 2;
} else {
// j位置的字符和i的不相等,那么就不会在dp[i + 1][j - 1] 增加
// 此时最大的字符串长度要不然算上它也就是 dp[i + 1][j] 要不就去掉它dp[i][j - 1]
dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
}
}
}
return dp[0][n - 1];
}
}
5, 最长回文子串
class Solution {
public String longestPalindrome(String s) {
// ababa 求最长公共子串
int len = s.length();
String result = "";
// i < 9 0 1 2 3 4 5 6 7 8
for (int i = 0; i < len * 2 - 1; i++) {
int left = i / 2;// 依次遍历len * 2个中心 0 0 1 1 2 2 3 3 4
int right = left + i % 2; /// 0 1 1 2 2 3 3 4 4
while (left >= 0 && right < len && s.charAt(left) == s.charAt(right)) {
String tmp = s.substring(left, right + 1);
if (tmp.length() > result.length()) {
result = tmp;
}
left--;
right++;
}
}
return result;
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/92848.html