leecode更新
This commit is contained in:
parent
013a1161d1
commit
600003ba7f
|
|
@ -0,0 +1,275 @@
|
||||||
|
package com.markilue.leecode.dynamic;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.dynamic
|
||||||
|
*@Author: dingjiawen
|
||||||
|
*@CreateTime: 2022-12-16 09:51
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣718题 最长重复子数组:
|
||||||
|
* 给两个整数数组 nums1 和 nums2 ,返回 两个数组中 公共的 、长度最长的子数组的长度。
|
||||||
|
* 经过测试子数组必须连续,即[3,2,1]和[3,1,2,1],其最长子数组为2而不是3
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T29_FindLength {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
int[] nums1 = {1, 2, 3, 2, 1};
|
||||||
|
int[] nums2 = {3, 2, 1, 4, 7};
|
||||||
|
System.out.println(findLength1(nums1, nums2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test1() {
|
||||||
|
int[] nums1 = {1,2,3,1,2,1};
|
||||||
|
int[] nums2 = {3,2,1,4,7};
|
||||||
|
System.out.println(findLength2(nums1, nums2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:最长子数组既然必须要求是连续的,那么跟28其实是比较类似的,就是需要找到对应的情况
|
||||||
|
* 比如[3,2,1]和[3,2,3,2,1],代码随想录的思路是,直接全都遍历了就知道了,所以时间复杂度O(N*M)
|
||||||
|
* TODO 代码随想录动态规划法:题目中说的子数组,其实就是连续子序列。这种问题动规最拿手
|
||||||
|
* (1)dp定义:dp[i][j] 表示以下标i - 1为结尾的A,和以下标j - 1为结尾的B,最长重复子数组长度为dp[i][j]。
|
||||||
|
* (特别注意: “以下标i - 1为结尾的A” 标明一定是 以A[i-1]为结尾的字符串)
|
||||||
|
* 其实dp[i][j]的定义也就决定着,我们在遍历dp[i][j]的时候i 和 j都要从1开始。
|
||||||
|
* (2)dp状态转移方程:即当A[i - 1] 和B[j - 1]相等的时候,dp[i][j] = dp[i - 1][j - 1] + 1;
|
||||||
|
* (3)dp初始化:根据dp[i][j]的定义,dp[i][0] 和dp[0][j]其实都是没有意义的!
|
||||||
|
* 为了方便递归公式dp[i][j] = dp[i - 1][j - 1] + 1所以dp[i][0] 和dp[0][j]初始化为0。
|
||||||
|
* (4)dp遍历顺序:外层for循环遍历A,内层for循环遍历B。
|
||||||
|
* (5)dp举例推导:A: [1,2,3,2,1],B: [3,2,1,4,7]为例
|
||||||
|
* B: 3 2 1 4 7
|
||||||
|
* A: 0 0 0 0 0 0
|
||||||
|
* 1 0 0 0 1 0 0
|
||||||
|
* 2 0 0 1 0 0 0
|
||||||
|
* 3 0 1 0 0 0 0
|
||||||
|
* 2 0 1 2 0 0 0
|
||||||
|
* 1 0 0 0 3 0 0
|
||||||
|
* 速度击败71.18%,内存击败24.68%
|
||||||
|
* 时间复杂度为O(N*M)
|
||||||
|
* @param nums1
|
||||||
|
* @param nums2
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int findLength(int[] nums1, int[] nums2) {
|
||||||
|
|
||||||
|
int[][] dp = new int[nums1.length + 1][nums2.length + 1];
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
for (int i = 1; i < dp.length; i++) {
|
||||||
|
for (int j = 1; j < dp[0].length; j++) {
|
||||||
|
if (nums1[i - 1] == nums2[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1;
|
||||||
|
if (result < dp[i][j]) result = dp[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 滚动数组优化思路:
|
||||||
|
*速度击败44.24%,内存击败88.2%
|
||||||
|
* @param nums1
|
||||||
|
* @param nums2
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int findLength1(int[] nums1, int[] nums2) {
|
||||||
|
|
||||||
|
int[] dp = new int[nums2.length + 1];
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
for (int i = 1; i < nums1.length + 1; i++) {
|
||||||
|
for (int j = nums2.length + 1 - 1; j >= 1; j--) {
|
||||||
|
if (nums1[i - 1] == nums2[j - 1]) {
|
||||||
|
dp[j] = dp[j - 1] + 1;
|
||||||
|
}else {
|
||||||
|
dp[j]=0; //如果不等需要重新赋值,避免不覆盖的情况;而二维的时候不用,因为不用重复利用
|
||||||
|
}
|
||||||
|
if (result < dp[j]) result = dp[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方 滑动窗口法:从A来一遍又从B来一遍,目的是防止[3,2,1]和[3,2,3,2,1],出现两次3,2的情况
|
||||||
|
* 时间复杂度O((N+M)*min(N,M)),空间复杂度O(1)
|
||||||
|
* 速度击败38.34%,内存击败84.78%
|
||||||
|
* @param nums1
|
||||||
|
* @param nums2
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int findLength2(int[] nums1, int[] nums2) {
|
||||||
|
int n = nums1.length, m = nums2.length;
|
||||||
|
int ret = 0;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
int len = Math.min(m, n - i);
|
||||||
|
int maxlen = maxLength(nums1, nums2, i, 0, len);
|
||||||
|
ret = Math.max(ret, maxlen);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < m; i++) {
|
||||||
|
int len = Math.min(n, m - i);
|
||||||
|
int maxlen = maxLength(nums1, nums2, 0, i, len);
|
||||||
|
ret = Math.max(ret, maxlen);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//寻找A从addA开始和B从addB开始,连续相同的最大值
|
||||||
|
public int maxLength(int[] A, int[] B, int addA, int addB, int len) {
|
||||||
|
int ret = 0, k = 0;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
if (A[addA + i] == B[addB + i]) {
|
||||||
|
k++;
|
||||||
|
} else {
|
||||||
|
k = 0;
|
||||||
|
}
|
||||||
|
ret = Math.max(ret, k);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方二分查找+哈希表法,不细研究:
|
||||||
|
* 核心思想是如果数组 A 和 B 有一个长度为 k 的公共子数组,那么它们一定有长度为 j <= k 的公共子数组。
|
||||||
|
* 这样我们可以通过二分查找的方法找到最大的 k。
|
||||||
|
*/
|
||||||
|
int mod = 1000000009;
|
||||||
|
int base = 113;
|
||||||
|
|
||||||
|
public int findLength3(int[] A, int[] B) {
|
||||||
|
int left = 1, right = Math.min(A.length, B.length) + 1;
|
||||||
|
while (left < right) {
|
||||||
|
int mid = (left + right) >> 1;
|
||||||
|
if (check(A, B, mid)) {
|
||||||
|
left = mid + 1;
|
||||||
|
} else {
|
||||||
|
right = mid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return left - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean check(int[] A, int[] B, int len) {
|
||||||
|
long hashA = 0;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
hashA = (hashA * base + A[i]) % mod;
|
||||||
|
}
|
||||||
|
Set<Long> bucketA = new HashSet<Long>();
|
||||||
|
bucketA.add(hashA);
|
||||||
|
long mult = qPow(base, len - 1);
|
||||||
|
for (int i = len; i < A.length; i++) {
|
||||||
|
hashA = ((hashA - A[i - len] * mult % mod + mod) % mod * base + A[i]) % mod;
|
||||||
|
bucketA.add(hashA);
|
||||||
|
}
|
||||||
|
long hashB = 0;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
hashB = (hashB * base + B[i]) % mod;
|
||||||
|
}
|
||||||
|
if (bucketA.contains(hashB)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (int i = len; i < B.length; i++) {
|
||||||
|
hashB = ((hashB - B[i - len] * mult % mod + mod) % mod * base + B[i]) % mod;
|
||||||
|
if (bucketA.contains(hashB)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用快速幂计算 x^n % mod 的值
|
||||||
|
public long qPow(long x, long n) {
|
||||||
|
long ret = 1;
|
||||||
|
while (n != 0) {
|
||||||
|
if ((n & 1) != 0) {
|
||||||
|
ret = ret * x % mod;
|
||||||
|
}
|
||||||
|
x = x * x % mod;
|
||||||
|
n >>= 1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方题解中,最快的方法:
|
||||||
|
* 似乎是二分查找+哈希表法
|
||||||
|
* 5ms
|
||||||
|
* 速度击败100%,内存击败82.24%
|
||||||
|
*/
|
||||||
|
long a = 13131;//形象地说,就是把 S 看成一个类似 base 进制的数(左侧为高位,右侧为低位),它的十进制值就是这个它的哈希值。
|
||||||
|
|
||||||
|
int N;
|
||||||
|
int M;
|
||||||
|
|
||||||
|
public int findLength4(int[] nums1, int[] nums2) {
|
||||||
|
N = nums1.length;
|
||||||
|
M = nums2.length;
|
||||||
|
|
||||||
|
int l = 0;
|
||||||
|
int r = Math.min(N, M);
|
||||||
|
|
||||||
|
while(l < r){
|
||||||
|
int mid = l + r + 1 >> 1;
|
||||||
|
//寻找有没有长度为k的公共子数组,找到了就说明可能有更大的
|
||||||
|
if(findDup(nums1, nums2, mid)) l = mid;
|
||||||
|
else r = mid - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean findDup(int[] nums1, int[] nums2, int len){
|
||||||
|
//为了便于理解进行举例:若nums1={1,2,3,1,2,1};nums2={3,2,1,4,7}
|
||||||
|
long h1 = 0;
|
||||||
|
long h2 = 0;
|
||||||
|
long al = 1;
|
||||||
|
|
||||||
|
Set<Long> set = new HashSet<>();
|
||||||
|
|
||||||
|
//计算[0-len]的nums1子数组哈希值
|
||||||
|
for(int i = 0; i < len; i++){
|
||||||
|
//a进制下的123
|
||||||
|
h1 = h1 * a + nums1[i];
|
||||||
|
//a进制下的1000
|
||||||
|
al = al * a;
|
||||||
|
}
|
||||||
|
set.add(h1);
|
||||||
|
|
||||||
|
//计算所有长度为len的子数组哈希值
|
||||||
|
for(int i = 1; i <= N - len; i++){
|
||||||
|
//以i=1为例
|
||||||
|
h1 = h1 * a;//1230
|
||||||
|
h1 = h1 - nums1[i - 1] * al;//1230-1000
|
||||||
|
h1 = h1 + nums1[i + len - 1];//231
|
||||||
|
set.add(h1);
|
||||||
|
}
|
||||||
|
//计算[0-len]的nums1子数组哈希值
|
||||||
|
for(int i = 0; i < len; i++) h2 = h2 * a + nums2[i];
|
||||||
|
|
||||||
|
if(set.contains(h2)) return true;
|
||||||
|
//计算所有len长的的nums2子数组哈希值
|
||||||
|
for(int i = 1; i <= M - len; i++){
|
||||||
|
h2 = h2 * a;
|
||||||
|
h2 = h2 - nums2[i - 1] * al;
|
||||||
|
h2 = h2 + nums2[i + len - 1];
|
||||||
|
|
||||||
|
if(set.contains(h2)) return true;//只要找到了就返回找到
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,230 @@
|
||||||
|
package com.markilue.leecode.dynamic;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@BelongsProject: Leecode
|
||||||
|
*@BelongsPackage: com.markilue.leecode.dynamic
|
||||||
|
*@Author: dingjiawen
|
||||||
|
*@CreateTime: 2022-12-16 12:51
|
||||||
|
*@Description:
|
||||||
|
* TODO 力扣1143题 最长公共子序列:
|
||||||
|
* 给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。
|
||||||
|
* 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
|
||||||
|
* 例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。
|
||||||
|
* 两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。
|
||||||
|
*@Version: 1.0
|
||||||
|
*/
|
||||||
|
public class T30_LongestCommonSubsequence {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test(){
|
||||||
|
String text2 = "abcacde";
|
||||||
|
String text1 = "acfe";
|
||||||
|
System.out.println(longestCommonSubsequence1(text1,text2));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test1(){
|
||||||
|
String text2 = "abcba";
|
||||||
|
String text1 = "abcbcba";
|
||||||
|
System.out.println(longestCommonSubsequence1(text1,text2));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 思路:与T29类似,只是将连续条件去掉了,变得可以不连续:
|
||||||
|
* TODO 动态规划五部曲:
|
||||||
|
* (1)dp定义:dp[i][j]表示以i-1结尾的text1和以j-1结尾的text2的最长公共子序列
|
||||||
|
* (2)dp状态转移方程: for j in (0,len-(i-1) ) if(num[i-1]==num[i-1+j:]) dp[i][j]=max(dp[i-1])+1
|
||||||
|
* (3)dp初始化:dp[0]=0
|
||||||
|
* (4)dp遍历顺序:两个for可以随意交换顺序
|
||||||
|
* (5)dp举例推导:以 text2 = "abcacde", text1 = "acfe" 为例
|
||||||
|
* text2: a b c a c d e
|
||||||
|
* text1: 0 0 0 0 0 0 0 0
|
||||||
|
* a: 0 1 1 1 1 1 1 1
|
||||||
|
* c: 0 1 1 2 2 2 2 2
|
||||||
|
* f: 0 1 1 2 2 2 2 2
|
||||||
|
* e: 0 1 1 2 2 2 2 3
|
||||||
|
* 速度击败39.62%,内存击败47.86% 11ms
|
||||||
|
* @param text1
|
||||||
|
* @param text2
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int longestCommonSubsequence(String text1, String text2) {
|
||||||
|
|
||||||
|
int[][] dp = new int[text1.length() + 1][text2.length() + 1];
|
||||||
|
|
||||||
|
for (int i = 1; i < text1.length()+1; i++) {
|
||||||
|
char char1 = text1.charAt(i-1);
|
||||||
|
for (int j = 1; j < text2.length() + 1; j++) {
|
||||||
|
if(char1==text2.charAt(j-1)){
|
||||||
|
//不要text1[i-1]大,还是不要text2[j-1]大,还是都要大
|
||||||
|
dp[i][j]=Math.max(dp[i][j-1],Math.max(dp[i-1][j],dp[i-1][j-1]+1));
|
||||||
|
}else {
|
||||||
|
//不要text1[i-1]大,还是不要text2[j-1]大
|
||||||
|
dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[text1.length()][text2.length()];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对于自己的浅浅优化一下:不需要判断不要text2[j-1]大,
|
||||||
|
* 因为他事实上取决于它的[j-2]和[i-1][j-2]谁大,所以他一定比[i-1]+1小
|
||||||
|
* 速度击败65.48%,内存击败34.92% 10ms
|
||||||
|
* @param text1
|
||||||
|
* @param text2
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int longestCommonSubsequence1(String text1, String text2) {
|
||||||
|
|
||||||
|
int[][] dp = new int[text1.length() + 1][text2.length() + 1];
|
||||||
|
|
||||||
|
for (int i = 1; i < text1.length()+1; i++) {
|
||||||
|
char char1 = text1.charAt(i-1);
|
||||||
|
for (int j = 1; j < text2.length() + 1; j++) {
|
||||||
|
if(char1==text2.charAt(j-1)){
|
||||||
|
//不要text1[i-1]大,还是都要大
|
||||||
|
dp[i][j]=Math.max(dp[i][j-1],dp[i-1][j-1]+1);
|
||||||
|
}else {
|
||||||
|
//不要text1[i-1]大,还是不要text2[j-1]大
|
||||||
|
dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[text1.length()][text2.length()];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对于代码随想录进一步优化一下:不需要判断dp[i][j]=Math.max(dp[i][j-1],dp[i-1][j-1]+1);
|
||||||
|
* 因为他事实上dp[i-1][j-1]+1一定比dp[i][j-1]大
|
||||||
|
* 速度击败77.38%,内存击败34.92% 9ms
|
||||||
|
* @param text1
|
||||||
|
* @param text2
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int longestCommonSubsequence2(String text1, String text2) {
|
||||||
|
|
||||||
|
int[][] dp = new int[text1.length() + 1][text2.length() + 1];
|
||||||
|
|
||||||
|
for (int i = 1; i < text1.length()+1; i++) {
|
||||||
|
char char1 = text1.charAt(i-1);
|
||||||
|
for (int j = 1; j < text2.length() + 1; j++) {
|
||||||
|
if(char1==text2.charAt(j-1)){
|
||||||
|
//不要text1[i-1]大,还是都要大
|
||||||
|
dp[i][j]=dp[i-1][j-1]+1;
|
||||||
|
}else {
|
||||||
|
//不要text1[i-1]大,还是不要text2[j-1]大
|
||||||
|
dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[text1.length()][text2.length()];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 一维dp数组优化
|
||||||
|
* 速度击败77.38%,内存击败97.17%
|
||||||
|
* @param text1
|
||||||
|
* @param text2
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int longestCommonSubsequence3(String text1, String text2) {
|
||||||
|
int n1 = text1.length();
|
||||||
|
int n2 = text2.length();
|
||||||
|
|
||||||
|
// 多从二维dp数组过程分析
|
||||||
|
// 关键在于 如果记录 dp[i - 1][j - 1]
|
||||||
|
// 因为 dp[i - 1][j - 1] <!=> dp[j - 1] <=> dp[i][j - 1]
|
||||||
|
int [] dp = new int[n2 + 1];
|
||||||
|
|
||||||
|
for(int i = 1; i <= n1; i++){
|
||||||
|
|
||||||
|
// 这里pre相当于 dp[i - 1][j - 1]
|
||||||
|
int pre = dp[0];
|
||||||
|
for(int j = 1; j <= n2; j++){
|
||||||
|
|
||||||
|
//用于给pre赋值
|
||||||
|
int cur = dp[j];
|
||||||
|
if(text1.charAt(i - 1) == text2.charAt(j - 1)){
|
||||||
|
//这里pre相当于dp[i - 1][j - 1] 千万不能用dp[j - 1] !!
|
||||||
|
//或者倒序遍历也行
|
||||||
|
dp[j] = pre + 1;
|
||||||
|
} else{
|
||||||
|
// dp[j] 相当于 dp[i - 1][j]
|
||||||
|
// dp[j - 1] 相当于 dp[i][j - 1]
|
||||||
|
dp[j] = Math.max(dp[j], dp[j - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//更新dp[i - 1][j - 1], 为下次使用做准备
|
||||||
|
pre = cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return dp[n2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 官方题解中合理且最快的方法:本质上还是动态规划,
|
||||||
|
* 但是优化在选取text长度最小的作为内层for,并将string变成数组后进行判断
|
||||||
|
* 速度击败99.96%,内存击败98.16% 3ms
|
||||||
|
* @param text1
|
||||||
|
* @param text2
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int longestCommonSubsequence4(String text1, String text2) {
|
||||||
|
//动态规划
|
||||||
|
//f(n) f(n-1)
|
||||||
|
//f(1) 递推
|
||||||
|
//确保text1最长
|
||||||
|
if(text1.length()<text2.length()){
|
||||||
|
return longestCommonSubsequence4(text2, text1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
char []chs1=text1.toCharArray();
|
||||||
|
char []chs2=text2.toCharArray();//转换字符串直接操作
|
||||||
|
int m=chs1.length;//记录长度1
|
||||||
|
int n=chs2.length;//记录长度2
|
||||||
|
int []dp=new int[n];//动态化,默认都是0
|
||||||
|
//abcde m
|
||||||
|
//axe n
|
||||||
|
//xab n
|
||||||
|
//abcde
|
||||||
|
//a a在text1里面,dp[0]=1
|
||||||
|
//x x不在在text1里面,dp[0]=0
|
||||||
|
|
||||||
|
//abcde m f(n) f(n-1)
|
||||||
|
//ax x不在在text1里面 dp[n]=dp[n-1]
|
||||||
|
//xa a在text1里面 dp[n]=dp[n-1]+1
|
||||||
|
int pre=0;//记录上一个
|
||||||
|
int cur=0;//当下一个
|
||||||
|
for(int i=0;i<m;i++){
|
||||||
|
char c=chs1[i];//取出第一个字母
|
||||||
|
if(c==chs2[0]){
|
||||||
|
dp[0]=1;
|
||||||
|
}
|
||||||
|
pre=dp[0];//记录上一个
|
||||||
|
for(int j=1;j<n;j++){//跳过第一个字符
|
||||||
|
cur=dp[j];//当前的数据默认0
|
||||||
|
if(c==chs2[j]){
|
||||||
|
dp[j]=pre+1;//dp[n]=dp[n-1]+1
|
||||||
|
}else{
|
||||||
|
dp[j]=Math.max(cur,dp[j-1]);//保存最大值
|
||||||
|
}
|
||||||
|
pre=cur;//记录上一个
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dp[n-1];//返回最后一个
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue