Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

动态规划

非动态规划专栏

最大子数组和

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组是数组中的一个连续部分。

示例 1:

1
2
3
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public int maxSubArray(int[] nums) {
/**
dp[i]定义为以nums[i]结尾的最大子数组和
dp[i]=Math.max(dp[i-1]+nums[i],nums[i]);
以nums[i]结尾的最大子数组和,如果dp[i-1]>0,dp[i]=dp[i-1]+nums[i]
如果dp[i-1]<0,dp[i-1]反而是累赘,不要它了,只要nums[i];
dp[0]=nums[0];

*/
if (nums.length == 1) {
return nums[0];
}
int dp[] = new int[nums.length];
dp[0] = nums[0];

int res = dp[0];
for (int i = 1; i < nums.length; i++) {
dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
res = Math.max(res, dp[i]);
}

return res;

}
}

跳跃游戏 II

给定一个长度为 n0 索引整数数组 nums。初始位置为 nums[0]

每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说,如果你在索引 i 处,你可以跳转到任意 (i + j) 处:

  • 0 <= j <= nums[i]
  • i + j < n

返回到达 n - 1 的最小跳跃次数。测试用例保证可以到达 n - 1

示例 1:

1
2
3
4
输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public int jump(int[] nums) {
/**
dp[i]定义为到达下标i的位置需要的最小次数。注意是次数
最小问题,初始化最大值。
如果j在(0,i)之间,且j+nums[j]>=i的话,说明j可以直接跳到i
dp[i]=Math.min(dp[i],dp[j]+1);
*/
int dp[] = new int[nums.length];
Arrays.fill(dp, 1000000);
dp[0] = 0;
for (int i = 1; i < nums.length; i++) {
for (int j = 0; j < i; j++) {
if (j + nums[j] >= i) {
dp[i] = Math.min(dp[i], dp[j] + 1);
}
}
}
return dp[nums.length - 1];
}
}

爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 12 个台阶。你有多少种不同的方法可以爬到楼顶呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public int climbStairs(int n) {
if (n <= 2) {
return n;
}
/**
dp[i]定义为到达第i阶的总方法数量
dp[i]=dp[i-1]+dp[i-2]
到达第i阶,可以从i-1来,也可以从1-2来。
dp[0]=0;
dp[1]=1;
dp[2]=2;
*/
int dp[] = new int[n + 1];
dp[1] = 1;
dp[2] = 2;
for (int i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
}

杨辉三角

给定一个非负整数 numRows生成「杨辉三角」的前 numRows 行。

在「杨辉三角」中,每个数是它左上方和右上方的数的和。

image-20250809173943988

示例 1:

1
2
输入: numRows = 5
输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution {
public List<List<Integer>> generate(int numRows) {
/**
没有显式用到dp数组
显示的话是dp[i][j]=dp[i-1][j-1]+dp[i-1][j]
*/
List<List<Integer>> res=new ArrayList<>();

for(int i=0;i<numRows;i++){
List<Integer> list=new ArrayList<>();
for(int j=0;j<=i;j++){
if(j==0||j==i){
list.add(1);
}else{
list.add(res.get(i-1).get(j-1)+res.get(i-1).get(j));
}
}
res.add(list);
}
return res;
}
}

打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

示例 1:

1
2
3
4
输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
public int rob(int[] nums) {

if (nums.length == 0) {
return 0;
}
if (nums.length == 1) {
return nums[0];
}
/**
定义dp[i]为偷下标为i的房间的最大收益
dp[i]=Math.max(dp[i-2]+nums[i],dp[i-1]);
如果偷当前房间,那么收益为dp[i-2]+nums[i];
如果不偷当前房间,收益为dp[i-1],看看谁大。
dp[0]=nums[0];
dp[1] = Math.max(dp[0], nums[1]);
*/
int dp[] = new int[nums.length];
dp[0] = nums[0];
dp[1] = Math.max(dp[0], nums[1]);

for (int i = 2; i < nums.length; i++) {
dp[i] = Math.max(dp[i - 1], nums[i] + dp[i - 2]);
}
return dp[nums.length - 1];

}
}

完全平方数

给你一个整数 n ,返回 和为 n 的完全平方数的最少数量

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,14916 都是完全平方数,而 311 不是。

示例 1:

1
2
3
输入:n = 12
输出:3
解释:12 = 4 + 4 + 4

示例 2:

1
2
3
输入:n = 13
输出:2
解释:13 = 4 + 9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
public int numSquares(int n) {
/**
这是最小最大问题,所有初始化要考虑清楚,而且没有nums数组对应dp的下标
所以dp的长度要+1;for循环条件加个=号
dp[i]定义为和为i所需的最小平方数,注意是数量
dp[i]初始化为dp[i] = i;因为和为i所需的最小平方数就是i个1
dp[i]=Math.min(dp[i-j*j]+1,dp[i]);
*/
int dp[] = new int[n + 1];

for(int i=0;i<=n;i++){
dp[i]=i;
}
for (int i = 0; i <= n; i++) {
for (int j = 0; j < i; j++) {
if ((i - j * j) >= 0) {
dp[i] = Math.min(dp[i], dp[i - j * j] + 1);
}

}
}
return dp[n];
}
}

零钱兑换

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1

你可以认为每种硬币的数量是无限的。

示例 1:

1
2
3
输入:coins = [1, 2, 5], amount = 11
输出:3
解释:11 = 5 + 5 + 1

解法1:dp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution {
public int coinChange(int[] coins, int amount) {
/**

dp[i]定义为凑成i所需要的最少金币;
最小最大问题要考虑初始化,管他什么求最小初始化成最大就行了。
dp[i]=dp[i-coin]+1,dp[i] 哪个更小
dp[0]=0;
*/
int dp[]=new int[amount+1];
Arrays.fill(dp,Integer.MAX_VALUE-100);//这里是因为Integer.MAX_VALUE+1会溢出
dp[0]=0;
for(int i=1;i<=amount;i++){
for(int coin:coins){
if((i-coin)>=0)
dp[i]=Math.min(dp[i],dp[i-coin]+1);
}
}
return dp[amount]==Integer.MAX_VALUE-100?-1:dp[amount];
}
}

解法2:回溯

参考组合总和,那个是求出所有总和,这个是求组合的元素最小个数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
private int pdmin = Integer.MAX_VALUE;

public int coinChange(int[] coins, int amount) {
List<Integer> cur = new ArrayList<>();
huisu(coins, amount, cur, 0, 0);
return pdmin == Integer.MAX_VALUE ? -1 : pdmin;
}

public void huisu(int[] coins, int amount, List<Integer> cur, int sum, int index) {
if (sum == amount) {
pdmin = Math.min(pdmin, cur.size());
return;
}
if (sum > amount) {
return;
}
for (int i = index; i < coins.length; i++) {
cur.add(coins[i]);
huisu(coins, amount, cur, sum + coins[i], i);
cur.remove(cur.size() - 1);
}
}
}

单词拆分

给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true

注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。

示例 1:

1
2
3
输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以由 "leet" 和 "code" 拼接成。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
/**
定义dp[i]表示前i个字符能否被正确拆分
dp[i]=dp[j]&&j...i在dict里面
表示如果前j个字符能被拆分,而且(j...i)还在wordDict里面,那么dp[i]能被拆分
dp[0]=true,空串能被拆分
*/

boolean dp[] = new boolean[s.length() + 1];
dp[0] = true;
for (int i = 1; i <= s.length(); i++) {
for (int j = 0; j < i; j++) {
dp[i] |= dp[j] && wordDict.contains(s.substring(j, i));//注意这里是||
}
}
return dp[s.length()];
}
}

最长递增子序列

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列 是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

示例 1:

1
2
3
输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。

示例 2:

1
2
输入:nums = [0,1,0,3,2,3]
输出:4

示例 3:

1
2
输入:nums = [7,7,7,7,7,7,7]
输出:1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public int lengthOfLIS(int[] nums) {
/**
最长问题注意初始化
dp[i]定义为以nums[i]结尾的最长连续子序列长度
dp[i]=nums[j]<nums[i]?:dp[j]+1:0
如果在(0,i)内有一个nums[j]<nums[i],说明nums[i]可以接在以j结尾的后面
每一个nums[i]都可以以自身作为结尾,即dp[]=1;
*/
int dp[] = new int[nums.length];
Arrays.fill(dp, 1);
int max = dp[0];
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[j] + 1, dp[i]);

}

}
max = Math.max(max, dp[i]);
}
return max;

}
}

乘积最大子数组

给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续 子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

测试用例的答案是一个 32-位 整数。

示例 1:

1
2
3
输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。

示例 2:

1
2
3
输入: nums = [-2,0,-1]
输出: 0
解释: 结果不能为 2, 因为 [-2,-1] 不是子数组。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Solution {
public int maxProduct(int[] nums) {
/**
最大问题
维护两个dp数组,因为原本是最大的数,结果遇到一个负数就g了
dpMax[i]定义为以nums[i]结尾的最大乘积
dpMin[i]定义为以nums[i]结尾的最小乘积
dpMax有三种情况:
1:只要当前元素
2:当前元素是负数,x dpMin变为最大
3:当前元素是正数,x dpMax变最大。
dpMax的三种情况同理
dpMax[i]=Math.max(Math.max(nums[i]*dpMax[i-1],nums[i]*dpMin[i-1]),nums[i]);
dpMin[i]=Nath.min(Math.min(nums[i]*dpMax[i-1],nums[i]*dpMin[i-1]),nums[i])
*/
int dpMax[] = new int[nums.length];
int dpMin[] = new int[nums.length];
dpMax[0] = dpMin[0] = nums[0];
int res = dpMax[0];
for (int i = 1; i < nums.length; i++) {
dpMax[i] = Math.max(Math.max(nums[i] * dpMax[i - 1], nums[i] * dpMin[i - 1]), nums[i]);
dpMin[i] = Math.min(Math.min(nums[i] * dpMax[i - 1], nums[i] * dpMin[i - 1]), nums[i]);
res = Math.max(res, dpMax[i]);

}
return res;
}
}

分割等和子集(待学习)

给你一个 只包含正整数非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

示例 1:

1
2
3
输入:nums = [1,5,11,5]
输出:true
解释:数组可以分割成 [1, 5, 5] 和 [11] 。

示例 2:

1
2
3
输入:nums = [1,2,3,5]
输出:false
解释:数组不能分割成两个元素和相等的子集。

用回溯会超时

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public boolean canPartition(int[] nums) {
int sum = Arrays.stream(nums).sum();
if (sum % 2 == 1) {
return false;
}
int target = sum / 2;
List<List<Integer>> res = new ArrayList<>();
List<Integer> cur = new ArrayList<>();
huisu(res, nums, cur, target, 0, 0);
return res.size() != 0;
}

public void huisu(List<List<Integer>> res, int nums[], List<Integer> cur, int target, int sum, int index) {
if (sum == target) {
res.add(new ArrayList<>(cur));
return;
}
if (sum > target || index >= nums.length) {
return;
}
huisu(res, nums, cur, target, sum, index + 1);
cur.add(nums[index]);
huisu(res, nums, cur, target, sum + nums[index], index + 1);
cur.remove(cur.size() - 1);
}
}

最长有效括号(非DP)

给你一个只包含 '('')' 的字符串,找出最长有效(格式正确且连续)括号 子串 的长度。

左右括号匹配,即每个左括号都有对应的右括号将其闭合的字符串是格式正确的,比如 "(()())"

示例 1:

1
2
3
输入:s = "(()"
输出:2
解释:最长有效括号子串是 "()"

示例 2:

1
2
3
输入:s = ")()())"
输出:4
解释:最长有效括号子串是 "()()"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public int longestValidParentheses(String s) {
//用一个栈来保存下标
/**
初始化需要push(-1);
因为假如"()",遇到(入栈,遇到)出栈,出栈时下标是1,如果没有记录起始位置,那么就找不到括号的长度,标记起始位置-1,那么长度就算1-peek()=2;
一旦栈空了就要记录起始下标位置。
*/
Stack<Integer> stack = new Stack<>();
stack.push(-1);
int max = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == '(') {
stack.push(i);
} else {
stack.pop();
if (stack.isEmpty()) {
stack.push(i);
} else {
max = Math.max(max, i - stack.peek());
}
}
}
return max;
}
}

二维动态规划

不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

image-20250809201118388

1
2
输入:m = 3, n = 7
输出:28
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public int uniquePaths(int m, int n) {
/**
dp[i][j]定义为到达(i,j)的路径数量
dp[i][j]=dp[i][j-1]||dp[i-1][j]
dp[0][0]=0;
dp[0][1]=1;
dp[1][0]=1;

*/
int dp[][]=new int[m][n];
for(int i=0;i<n;i++){
dp[0][i]=1;
}
for(int i=0;i<m;i++){
dp[i][0]=1;
}
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
dp[i][j]=dp[i][j-1]+dp[i-1][j];
}
}
return dp[m-1][n-1];

}
}

最小路径和

给定一个包含非负整数的 *m* x *n* 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。

image-20250809201200109

1
2
3
输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。

示例 2:

1
2
输入:grid = [[1,2,3],[4,5,6]]
输出:12
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public int minPathSum(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
/**
dp[i][j]定义为到达(i,j)的最小路径和
dp[i][j]=dp[i-1][j]+dp[i][j-1]+grid[i][j]
*/
int dp[][] = new int[m][n];
dp[0][0] = grid[0][0];
for (int i = 1; i < n; i++) {
dp[0][i] = dp[0][i - 1] + grid[0][i];
}
for (int i = 1; i < m; i++) {
dp[i][0] = dp[i - 1][0] + grid[i][0];
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = Math.min(dp[i - 1][j] + grid[i][j], dp[i][j - 1] + grid[i][j]);
}
}
return dp[m - 1][n - 1];
}
}

最长回文子串

给你一个字符串 s,找到 s 中最长的 回文 子串。

示例 1:

1
2
3
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

示例 2:

1
2
输入:s = "cbbd"
输出:"bb"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class Solution {
public String longestPalindrome(String s) {
if (s == null || s.length() < 2)
return s;
/**
dp[i][j]定义为字符串i到j的子串是回文串;
单个字符一定是回文
两个字符需要判断是否相等
三个及三个以上需要判断两段字符一样的同时,夹在中间的子串也是回文
即dp[i][j]=(s.charAt(i)==s.charAt(j))&&dp[i+1][j-1];
*/
int n = s.length();
boolean[][] dp = new boolean[n][n];

// 记录最长回文子串的起始位置和长度
int start = 0;
int maxLen = 1;

// 初始化:单个字符都是回文
for (int i = 0; i < n; i++) {
dp[i][i] = true;
}

// 检查长度为2的子串
for (int i = 0; i < n - 1; i++) {
if (s.charAt(i) == s.charAt(i + 1)) {
dp[i][i + 1] = true;
start = i;
maxLen = 2;
}
}

// 检查长度大于等于3的子串
//abcdefgh len=8
//01234567
for (int len = 3; len <= n; len++) {
for (int i = 0; i <= n - len; i++) {
int j = i + len - 1;

if (s.charAt(i) == s.charAt(j) && dp[i + 1][j - 1]) {
dp[i][j] = true;
start = i;
maxLen = len;
}
}
}

return s.substring(start, start + maxLen);
}
}

最长公共子序列

给定两个字符串 text1text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

  • 例如,"ace""abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。

两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

示例 1:

1
2
3
输入:text1 = "abcde", text2 = "ace" 
输出:3
解释:最长公共子序列是 "ace" ,它的长度为 3 。

示例 2:

1
2
3
输入:text1 = "abc", text2 = "abc"
输出:3
解释:最长公共子序列是 "abc" ,它的长度为 3 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Solution {
public int longestCommonSubsequence(String text1, String text2) {
/**
定义dp[i][j]为,左边前i个字符与右边前j个字符的最长公共子序列
dp[i][j]=dp[i-1][j-1]+1 字符相同的情况,因为这个必然要成为公共子序列的一部分
dp[i][j]=max(dp[i-1][j],dp[i][j-1])字符不同的情况下,因为不同,所有两个字符不能同时要,所有只取一个就行了,取谁就看哪一个dp大。

注意注意!i和j是代表的个数,前i个,那么第i个的下标是i-1
*/
int m = text1.length();
int n = text2.length();
int dp[][] = new int[m + 1][n + 1];
//左边前0个字符与右边前n个字符的最长公共子序列=0;
//左边前m个字符与右边前0个字符的最长公共子序列=0;
//初始化已经是0
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (text1.charAt(i - 1) == text2.charAt(j - 1)) {
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[m][n];
}
}

编辑距离

给你两个单词 word1word2请返回将 word1 转换成 word2 所使用的最少操作数

你可以对一个单词进行如下三种操作:

  • 插入一个字符
  • 删除一个字符
  • 替换一个字符

示例 1:

1
2
3
4
5
6
输入:word1 = "horse", word2 = "ros"
输出:3
解释:
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Solution {
public int minDistance(String word1, String word2) {
/**
定义dp[i][j],左边前i个字符转换为右边前j个字符最小次数。
注意注意!,i是前i个字符,那么下标就算i-1;
左边前0个字符转换成右边前j个字符的最小次数是j,因为全部add
左边前i个字符转换成右边前0个字符的最小次数是i,因为全部是delete
如果左边第i个字符==右边第j个字符,不用转换
dp[i][j]=dp[i-1][j-1]
如果如果左边第i个字符!=右边第j个字符
有三种转换方式
替换、新增、删除
看谁次数最少
dp[i][j]=Math.min(Math.min(dp[i-1][j]+1,dp[i][j-1]+1),dp[i-1][j-1]+1);
*/
int m = word1.length();
int n = word2.length();
int dp[][] = new int[m + 1][n + 1];
for (int i = 0; i <= m; i++) {
dp[i][0] = i;
}
for (int i = 0; i <= n; i++) {
dp[0][i] = i;
}
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
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] + 1), dp[i - 1][j - 1] + 1);
}
}
}
return dp[m][n];
}
}

总结:

评论