10.15 复习
This commit is contained in:
parent
3d5587b297
commit
7417736f7a
135
src/main/java/All/Compress.java
Normal file
135
src/main/java/All/Compress.java
Normal file
@ -0,0 +1,135 @@
|
||||
package All;
|
||||
|
||||
/**
|
||||
* 题目: 443. 压缩字符串
|
||||
* 描述:给你一个字符数组 chars ,请使用下述算法压缩:
|
||||
*
|
||||
* 从一个空字符串 s 开始。对于 chars 中的每组 连续重复字符 :
|
||||
*
|
||||
* 如果这一组长度为 1 ,则将字符追加到 s 中。
|
||||
* 否则,需要向 s 追加字符,后跟这一组的长度。
|
||||
* 压缩后得到的字符串 s 不应该直接返回 ,需要转储到字符数组 chars 中。需要注意的是,如果组长度为 10 或 10 以上,则在 chars 数组中会被拆分为多个字符。
|
||||
*
|
||||
* 请在 修改完输入数组后 ,返回该数组的新长度。
|
||||
*
|
||||
* 你必须设计并实现一个只使用常量额外空间的算法来解决此问题。
|
||||
*
|
||||
* 注意:数组中超出返回长度的字符无关紧要,应予忽略。
|
||||
|
||||
示例 1:
|
||||
输入:chars = ["a","a","b","b","c","c","c"]
|
||||
输出:返回 6 ,输入数组的前 6 个字符应该是:["a","2","b","2","c","3"]
|
||||
解释:"aa" 被 "a2" 替代。"bb" 被 "b2" 替代。"ccc" 被 "c3" 替代。
|
||||
|
||||
注意:数组中超出返回长度的字符无关紧要,应予忽略。
|
||||
|
||||
* 链接:https://leetcode.cn/problems/string-compression/
|
||||
*/
|
||||
public class Compress {
|
||||
/*
|
||||
自己写的又臭又长
|
||||
*/
|
||||
public int compress2(char[] chars) {
|
||||
// Arrays.sort(chars);
|
||||
int cnt=1;
|
||||
char cur=chars[0];
|
||||
int read=1,write=0;
|
||||
while (read<chars.length){
|
||||
if(chars[read]==cur)
|
||||
cnt++;
|
||||
else {
|
||||
chars[write++]=cur;
|
||||
cur=chars[read];
|
||||
if(cnt==1){
|
||||
read++;
|
||||
continue;
|
||||
}
|
||||
StringBuilder sb=new StringBuilder();
|
||||
while (cnt!=0){
|
||||
int now=cnt%10;
|
||||
cnt/=10;
|
||||
sb.insert(0,now);
|
||||
}
|
||||
for (int i = 0; i < sb.length(); i++) {
|
||||
chars[write++]=sb.charAt(i);
|
||||
}
|
||||
cnt=1;
|
||||
}
|
||||
read++;
|
||||
}
|
||||
chars[write++]=cur;
|
||||
if(cnt!=1){
|
||||
StringBuilder sb=new StringBuilder();
|
||||
while (cnt!=0){
|
||||
int now=cnt%10;
|
||||
cnt/=10;
|
||||
sb.insert(0,now);
|
||||
}
|
||||
for (int i = 0; i < sb.length(); i++) {
|
||||
chars[write++]=sb.charAt(i);
|
||||
}
|
||||
}
|
||||
return write;
|
||||
}
|
||||
public int compress(char[] chars) {
|
||||
int write = 0; // 写指针
|
||||
int read = 0; // 读指针
|
||||
|
||||
while (read < chars.length) {
|
||||
char cur = chars[read];
|
||||
int count = 0;
|
||||
|
||||
// 统计连续相同字符
|
||||
while (read < chars.length && chars[read] == cur) {
|
||||
read++;
|
||||
count++;
|
||||
}
|
||||
|
||||
// 写入当前字符
|
||||
chars[write++] = cur;
|
||||
|
||||
// 如果数量大于 1,写入数字(多位数拆开)
|
||||
if (count > 1) {
|
||||
// 直接转字符串再逐位写入
|
||||
for (char c : String.valueOf(count).toCharArray()) {
|
||||
chars[write++] = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return write;
|
||||
}
|
||||
|
||||
private String compress1(char[] chars) {
|
||||
if (chars.length == 0) return "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
char current = chars[0];
|
||||
int cnt = 1;
|
||||
|
||||
for (int i = 1; i < chars.length; i++) {
|
||||
if (chars[i] == current) {
|
||||
cnt++;
|
||||
} else {
|
||||
sb.append(current);
|
||||
if (cnt > 1) sb.append(cnt);
|
||||
current = chars[i];
|
||||
cnt = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理最后一组字符
|
||||
sb.append(current);
|
||||
if (cnt > 1) sb.append(cnt);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
Compress solution = new Compress();
|
||||
char[] chars = {'a','b','c'};
|
||||
int res=solution.compress(chars);
|
||||
System.out.println(res);
|
||||
System.out.println(chars);
|
||||
}
|
||||
}
|
||||
33
src/main/java/All/FindTheWinner.java
Normal file
33
src/main/java/All/FindTheWinner.java
Normal file
@ -0,0 +1,33 @@
|
||||
package All;
|
||||
/**
|
||||
* 题目: 1823. 找出游戏的获胜者
|
||||
* 描述:共有 n 名小伙伴一起做游戏。小伙伴们围成一圈,按 顺时针顺序 从 1 到 n 编号。确切地说,从第 i 名小伙伴顺时针移动一位会到达第 (i+1) 名小伙伴的位置,其中 1 <= i < n ,从第 n 名小伙伴顺时针移动一位会回到第 1 名小伙伴的位置。
|
||||
* 游戏遵循如下规则:
|
||||
* 从第 1 名小伙伴所在位置 开始 。
|
||||
* 沿着顺时针方向数 k 名小伙伴,计数时需要 包含 起始时的那位小伙伴。逐个绕圈进行计数,一些小伙伴可能会被数过不止一次。
|
||||
* 你数到的最后一名小伙伴需要离开圈子,并视作输掉游戏。
|
||||
* 如果圈子中仍然有不止一名小伙伴,从刚刚输掉的小伙伴的 顺时针下一位 小伙伴 开始,回到步骤 2 继续执行。
|
||||
* 否则,圈子中最后一名小伙伴赢得游戏。
|
||||
* 给你参与游戏的小伙伴总数 n ,和一个整数 k ,返回游戏的获胜者。
|
||||
|
||||
示例 1:
|
||||
输入:n = 5, k = 2
|
||||
输出:3
|
||||
解释:游戏运行步骤如下:
|
||||
1) 从小伙伴 1 开始。
|
||||
2) 顺时针数 2 名小伙伴,也就是小伙伴 1 和 2 。
|
||||
3) 小伙伴 2 离开圈子。下一次从小伙伴 3 开始。
|
||||
4) 顺时针数 2 名小伙伴,也就是小伙伴 3 和 4 。
|
||||
5) 小伙伴 4 离开圈子。下一次从小伙伴 5 开始。
|
||||
6) 顺时针数 2 名小伙伴,也就是小伙伴 5 和 1 。
|
||||
7) 小伙伴 1 离开圈子。下一次从小伙伴 3 开始。
|
||||
8) 顺时针数 2 名小伙伴,也就是小伙伴 3 和 5 。
|
||||
9) 小伙伴 5 离开圈子。只剩下小伙伴 3 。所以小伙伴 3 是游戏的获胜者。
|
||||
|
||||
* 链接:https://leetcode.cn/problems/find-the-winner-of-the-circular-game/
|
||||
*/
|
||||
public class FindTheWinner {
|
||||
public int findTheWinner(int n, int k) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
140
src/main/java/All/GetLengthOfOptimalCompression.java
Normal file
140
src/main/java/All/GetLengthOfOptimalCompression.java
Normal file
@ -0,0 +1,140 @@
|
||||
package All;
|
||||
/**
|
||||
* 【题目描述】
|
||||
*
|
||||
* 给定一个仅包含大小写英文字母的字符串 s,
|
||||
* 你可以删除最多 k 个字符,以使得删除后压缩字符串的长度最小。
|
||||
*
|
||||
* 压缩规则如下(类似于 LeetCode 443 “字符串压缩”):
|
||||
* - 将连续出现的相同字符压缩为:字符 + 出现次数;
|
||||
* - 如果某个字符只出现一次,则不写次数;
|
||||
* - 例如:
|
||||
* "aabcccccaaa" 压缩后为 "a2bc5a3",长度为 7。
|
||||
*
|
||||
* 你可以选择删除字符串中的任意 k 个字符(也可以不删除),
|
||||
* 目标是使得压缩后的字符串长度最短。
|
||||
*
|
||||
* 【要求返回】
|
||||
* 删除最多 k 个字符后,压缩字符串的最短可能长度。
|
||||
*
|
||||
* 【示例】
|
||||
* 输入:s = "aabcccccaaa", k = 0
|
||||
* 输出:7
|
||||
* 解释:
|
||||
* 压缩后为 "a2bc5a3",长度为 7。
|
||||
*/
|
||||
|
||||
public class GetLengthOfOptimalCompression {
|
||||
private int minLen = Integer.MAX_VALUE;
|
||||
|
||||
/*
|
||||
“用回溯法(DFS)枚举所有可能的删除方式,
|
||||
对每个保留下来的字符串调用 compress1() 求压缩长度,
|
||||
最后取最小值。”
|
||||
会超时,时间复杂度非常大
|
||||
*/
|
||||
public int getLengthOfOptimalCompression(String s, int k) {
|
||||
if (s == null || s.length() == 0) return 0;
|
||||
char[] chars = s.toCharArray();
|
||||
dfs(chars, k, 0, new StringBuilder());
|
||||
return minLen;
|
||||
}
|
||||
|
||||
// 回溯枚举删除情况
|
||||
private void dfs(char[] s, int k, int index, StringBuilder current) {
|
||||
// 如果删除次数超过 k,直接剪枝
|
||||
if (k < 0) return;
|
||||
|
||||
// 到达字符串末尾
|
||||
if (index == s.length) {
|
||||
String compressed = compress1(current.toString().toCharArray());
|
||||
minLen = Math.min(minLen, compressed.length());
|
||||
return;
|
||||
}
|
||||
|
||||
// 选择1️⃣:保留当前字符
|
||||
current.append(s[index]);
|
||||
dfs(s, k, index + 1, current);
|
||||
current.setLength(current.length() - 1);
|
||||
|
||||
// 选择2️⃣:删除当前字符
|
||||
dfs(s, k - 1, index + 1, current);
|
||||
}
|
||||
|
||||
// 你的压缩逻辑,原样复用 ✅
|
||||
private String compress1(char[] chars) {
|
||||
if (chars.length == 0) return "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
char current = chars[0];
|
||||
int cnt = 1;
|
||||
|
||||
for (int i = 1; i < chars.length; i++) {
|
||||
if (chars[i] == current) {
|
||||
cnt++;
|
||||
} else {
|
||||
sb.append(current);
|
||||
if (cnt > 1) sb.append(cnt);
|
||||
current = chars[i];
|
||||
cnt = 1;
|
||||
}
|
||||
}
|
||||
|
||||
sb.append(current);
|
||||
if (cnt > 1) sb.append(cnt);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
标准解法是使用 动态规划(DP + 记忆化 DFS),时间复杂度 O(n²·k)。
|
||||
dp[i][k] = 从下标 i 开始,最多删除 k 个字符后,最短压缩长度
|
||||
从第 i 位开始枚举字符;
|
||||
统计连续相同字符出现次数 count;
|
||||
删除掉部分不同字符(消耗 k);
|
||||
更新最小压缩长度:
|
||||
dp[i][k] = min(
|
||||
dp[j+1][k - (段长 - count)] + 压缩该段的长度
|
||||
)
|
||||
*/
|
||||
public int getLengthOfOptimalCompression2(String s, int k) {
|
||||
int n = s.length();
|
||||
Integer[][] memo = new Integer[n][k + 1];
|
||||
return dfs(s.toCharArray(), 0, k, memo);
|
||||
}
|
||||
|
||||
private int dfs(char[] s, int i, int k, Integer[][] memo) {
|
||||
if (k < 0) return Integer.MAX_VALUE / 2; // 删除过多
|
||||
if (i >= s.length || s.length - i <= k) return 0; // 全删完
|
||||
if (memo[i][k] != null) return memo[i][k];
|
||||
|
||||
int res = Integer.MAX_VALUE;
|
||||
int[] cnt = new int[26];
|
||||
int most = 0;
|
||||
|
||||
// 从 i 开始,逐步扩展区间
|
||||
for (int j = i; j < s.length; j++) {
|
||||
int idx = s[j] - 'a';
|
||||
cnt[idx]++;
|
||||
most = Math.max(most, cnt[idx]);
|
||||
|
||||
int del = (j - i + 1) - most; // 删除不匹配字符
|
||||
if (del > k) continue;
|
||||
|
||||
res = Math.min(
|
||||
res,
|
||||
1 + numLength(most) + dfs(s, j + 1, k - del, memo)
|
||||
);
|
||||
}
|
||||
|
||||
return memo[i][k] = res;
|
||||
}
|
||||
|
||||
private int numLength(int x) {
|
||||
if (x <= 1) return 0;
|
||||
if (x < 10) return 1;
|
||||
if (x < 100) return 2;
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
@ -15,6 +15,7 @@ package binary_search;
|
||||
*/
|
||||
//不会
|
||||
//二刷不会
|
||||
//三刷不会
|
||||
public class FindMedianSortedArrays {
|
||||
|
||||
|
||||
@ -63,7 +64,7 @@ public class FindMedianSortedArrays {
|
||||
|
||||
// 每次比较 nums1 和 nums2 各自第 k/2 个候选(如果不足 k/2,则取末尾)
|
||||
int half = k / 2;
|
||||
int newIndex1 = Math.min(index1 + half, len1) - 1;
|
||||
int newIndex1 = Math.min(index1 + half, len1) - 1; //例如 index=0,要找第 3 个元素: → 索引 = 0 + 3 - 1 = 2。
|
||||
int newIndex2 = Math.min(index2 + half, len2) - 1;
|
||||
int pivot1 = nums1[newIndex1];
|
||||
int pivot2 = nums2[newIndex2];
|
||||
@ -80,4 +81,30 @@ public class FindMedianSortedArrays {
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
如果不考虑时间复杂度
|
||||
*/
|
||||
public int findKthMerge(int[] nums1, int[] nums2, int k) {
|
||||
int i = 0, j = 0, count = 0;
|
||||
int val = 0;
|
||||
|
||||
while (i < nums1.length || j < nums2.length) {
|
||||
int a = (i < nums1.length) ? nums1[i] : Integer.MAX_VALUE;
|
||||
int b = (j < nums2.length) ? nums2[j] : Integer.MAX_VALUE;
|
||||
|
||||
if (a <= b) {
|
||||
val = a;
|
||||
i++;
|
||||
} else {
|
||||
val = b;
|
||||
j++;
|
||||
}
|
||||
|
||||
count++;
|
||||
if (count == k) return val;
|
||||
}
|
||||
return -1; // 理论上不会走到这里
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ package binary_search;
|
||||
* 链接:https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/
|
||||
*/
|
||||
//二刷不会
|
||||
//三刷不会
|
||||
public class FindMin {
|
||||
|
||||
/**
|
||||
@ -29,7 +30,12 @@ public class FindMin {
|
||||
* 判断最小值在哪个区间
|
||||
*
|
||||
* 左侧有序情况:如果 nums[mid] >= nums[left],说明从 left 到 mid 是有序的,此时最小值不可能出现在有序部分,所以最小值一定在右半部分,因此更新 left = mid + 1。
|
||||
* 为什么说'此时最小值不可能出现在有序部分'? 因为 左边最小值此时是nums[left] 但是这里有个前提,一开始就判断了nums[left]>nums[right] ,故最小值肯定在右半段。
|
||||
*
|
||||
*
|
||||
* 旋转点在左侧情况:如果 nums[mid] < nums[left],说明中间部分处于旋转状态,即最小值可能出现在左半部分或就是 nums[mid],因此将 right 更新为 mid。
|
||||
* 为什么? 因为最小值肯定在旋转的区间内,4 5 6 7 0 1 2 ,最小值左边就是最大值。
|
||||
*
|
||||
* 退出条件
|
||||
*
|
||||
* 循环在 left == right 时退出,此时 nums[left] 就是整个数组的最小值。
|
||||
|
||||
@ -13,6 +13,7 @@ package dynamic_programming;
|
||||
* 链接:https://leetcode.cn/problems/partition-equal-subset-sum/
|
||||
*/
|
||||
//二刷不会
|
||||
//三刷会做
|
||||
public class CanPartition {
|
||||
public boolean canPartition1(int[] nums) {
|
||||
int total=0,target=0;
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
package dynamic_programming;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* 题目: 518. 零钱兑换 II (change)
|
||||
* 描述:给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。
|
||||
|
||||
@ -14,6 +14,7 @@ package dynamic_programming;
|
||||
*/
|
||||
//不会
|
||||
//二刷不会
|
||||
//三刷不会
|
||||
public class CountSubstrings {
|
||||
/**
|
||||
*布尔类型的dp[i][j]:表示区间范围[i,j] (注意是左闭右闭)的子串是否是回文子串
|
||||
|
||||
@ -14,6 +14,7 @@ package dynamic_programming;
|
||||
* 链接:https://leetcode.cn/problems/ones-and-zeroes/
|
||||
*/
|
||||
//二刷不会
|
||||
//三刷会做
|
||||
public class FindMaxForm {
|
||||
// 统计字符串中 '0' 和 '1' 的数量
|
||||
private int[] countZeroAndOne(String str) {
|
||||
|
||||
@ -20,6 +20,7 @@ package dynamic_programming;
|
||||
*/
|
||||
//二刷不会
|
||||
//三刷不会,数学转换很重要!
|
||||
//四刷会做
|
||||
public class FindTargetSumWays {
|
||||
|
||||
/**
|
||||
|
||||
@ -11,6 +11,7 @@ package dynamic_programming;
|
||||
|
||||
* 链接:https://leetcode.cn/problems/integer-break/
|
||||
*/
|
||||
//二刷不会
|
||||
public class IntegerBreak {
|
||||
public int integerBreak(int n) {
|
||||
//dp[i] 为正整数 i 拆分后的结果的最大乘积
|
||||
|
||||
@ -14,6 +14,7 @@ package dynamic_programming;
|
||||
* 链接:https://leetcode.cn/problems/is-subsequence/
|
||||
*/
|
||||
//不会
|
||||
//二刷会做
|
||||
public class IsSubsequence {
|
||||
//动态规划:转为求最长公共子序列,是否为s的长度
|
||||
public boolean isSubsequence(String s, String t) {
|
||||
@ -34,7 +35,6 @@ public class IsSubsequence {
|
||||
|
||||
/**
|
||||
* 我们用两个指针 i 遍历字符串 s,j 遍历字符串 t。初始均指向各自字符串的开头:
|
||||
*
|
||||
* 如果 s.charAt(i) == t.charAt(j),说明匹配上了,两个指针都往后走:i++, j++。
|
||||
* 否则,就只能在 t 上“跳过”这个字符,j++。
|
||||
* 当 i 走到 s.length() 时,说明 s 中的所有字符都在 t 中按顺序找到了,返回 true;否则,等 j 扫完 t 还没把 s 的所有字符匹配完,就返回 false。
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package dynamic_programming;
|
||||
/**
|
||||
* 题目: 152. 乘积最大子数组 (MaxProduct)
|
||||
* 描述:给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续 子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
|
||||
* 描述:给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
|
||||
* 测试用例的答案是一个 32-位 整数。
|
||||
|
||||
* 示例 1:
|
||||
@ -14,6 +14,7 @@ package dynamic_programming;
|
||||
//不会
|
||||
//二刷不会
|
||||
//三刷不会
|
||||
//四刷会做
|
||||
public class MaxProduct {
|
||||
|
||||
/**
|
||||
@ -60,9 +61,9 @@ public class MaxProduct {
|
||||
public static void main(String[] args) {
|
||||
MaxProduct sol = new MaxProduct();
|
||||
System.out.println(sol.maxProduct(new int[]{2, 3, -2, 4})); // 输出 6
|
||||
System.out.println(sol.maxProduct(new int[]{-2, 0, -1})); // 输出 0
|
||||
System.out.println(sol.maxProduct(new int[]{-2, 3, -4})); // 输出 24
|
||||
System.out.println(sol.maxProduct(new int[]{-1, -3, -10, 0, 60})); // 输出 60
|
||||
System.out.println(sol.maxProduct(new int[]{-2, -5, -2, -4, 3})); // 输出 240
|
||||
// System.out.println(sol.maxProduct(new int[]{-2, 0, -1})); // 输出 0
|
||||
// System.out.println(sol.maxProduct(new int[]{-2, 3, -4})); // 输出 24
|
||||
// System.out.println(sol.maxProduct(new int[]{-1, -3, -10, 0, 60})); // 输出 60
|
||||
// System.out.println(sol.maxProduct(new int[]{-2, -5, -2, -4, 3})); // 输出 240
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,6 +14,7 @@ package dynamic_programming;
|
||||
*/
|
||||
//不会
|
||||
//二刷不会
|
||||
//三刷会做
|
||||
public class MaxProfit4 {
|
||||
/**
|
||||
* 状态定义:
|
||||
|
||||
@ -11,6 +11,7 @@ package dynamic_programming;
|
||||
*/
|
||||
//不会
|
||||
//二刷不会
|
||||
//三刷会做
|
||||
public class MaximalSquare {
|
||||
/**
|
||||
* dp[i][j] 表示 以 (i, j) 作为右下角的最大全 1 正方形的边长
|
||||
|
||||
@ -11,7 +11,18 @@ package dynamic_programming;
|
||||
|
||||
* 链接:https://leetcode.cn/problems/delete-operation-for-two-strings/
|
||||
*/
|
||||
//二刷会做
|
||||
public class MinDistance {
|
||||
/**
|
||||
* 法一:转为LCS
|
||||
* 假设两个字符串的 最长公共子序列长度 是 LCS,
|
||||
* 那我们只要:
|
||||
* 把 word1 中那些 不在 LCS 里的字符 删除;
|
||||
* 把 word2 中那些 不在 LCS 里的字符 删除;
|
||||
* 就能让它们都变成 LCS 一样的字符串。
|
||||
* 因此最少删除步数公式:minDistance = (len1 - LCS) + (len2 - LCS)
|
||||
* = len1 + len2 - 2 * LCS
|
||||
*/
|
||||
public int minDistance(String word1, String word2) {
|
||||
int len1=word1.length(),len2=word2.length();
|
||||
int[][]dp=new int[len1+1][len2+1];
|
||||
@ -24,4 +35,28 @@ public class MinDistance {
|
||||
}
|
||||
return len1+len2-2*dp[len1][len2];
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接求最小删除步数
|
||||
* dp[i][j] = 让 word1 的前 i 个字符 和 word2 的前 j 个字符 变成相同字符串 所需的最少删除步数。
|
||||
*/
|
||||
public int minDistance2(String word1, String word2) {
|
||||
int len1 = word1.length(), len2 = word2.length();
|
||||
int[][] dp = new int[len1 + 1][len2 + 1];
|
||||
|
||||
// 初始化:任意一个为空,必须删完另一个
|
||||
for (int i = 0; i <= len1; i++) dp[i][0] = i;
|
||||
for (int j = 0; j <= len2; j++) dp[0][j] = j;
|
||||
|
||||
for (int i = 1; i <= len1; i++) {
|
||||
for (int j = 1; j <= len2; j++) {
|
||||
if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
|
||||
dp[i][j] = dp[i - 1][j - 1]; // 字符相等,无需删除
|
||||
} else {
|
||||
dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + 1; // 删除一个
|
||||
}
|
||||
}
|
||||
}
|
||||
return dp[len1][len2];
|
||||
}
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ import java.util.Arrays;
|
||||
*/
|
||||
//不会
|
||||
//二刷不会
|
||||
//三刷不会
|
||||
public class EraseOverlapIntervals {
|
||||
/**
|
||||
* 1.按结束时间排序
|
||||
|
||||
@ -41,7 +41,7 @@ public class LRUCache {
|
||||
/**
|
||||
* 双向链表节点
|
||||
*/
|
||||
class DLinkedNode {
|
||||
static class DLinkedNode {
|
||||
int key; // 保存 key:便于淘汰节点时同步从 cache 中删除
|
||||
int value; // 保存 value
|
||||
DLinkedNode prev; // 前驱
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user