-
Notifications
You must be signed in to change notification settings - Fork 212
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
nibnait
committed
Oct 29, 2020
1 parent
3551f23
commit 9d4a2a9
Showing
17 changed files
with
841 additions
and
57 deletions.
There are no files selected for viewing
131 changes: 131 additions & 0 deletions
131
src/main/java/algorithm_practice/LeetCode/code000/H072_编辑距离.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
package algorithm_practice.LeetCode.code000; | ||
|
||
import org.junit.Assert; | ||
import org.junit.Test; | ||
|
||
/* | ||
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。 | ||
你可以对一个单词进行如下三种操作: | ||
插入一个字符 | ||
删除一个字符 | ||
替换一个字符 | ||
示例 1: | ||
输入:word1 = "horse", word2 = "ros" | ||
输出:3 | ||
解释: | ||
horse -> rorse (将 'h' 替换为 'r') | ||
rorse -> rose (删除 'r') | ||
rose -> ros (删除 'e') | ||
示例 2: | ||
输入:word1 = "intention", word2 = "execution" | ||
输出:5 | ||
解释: | ||
intention -> inention (删除 't') | ||
inention -> enention (将 'i' 替换为 'e') | ||
enention -> exention (将 'n' 替换为 'x') | ||
exention -> exection (将 'n' 替换为 'c') | ||
exection -> execution (插入 'u') | ||
来源:力扣(LeetCode) | ||
链接:https://leetcode-cn.com/problems/edit-distance | ||
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 | ||
*/ | ||
public class H072_编辑距离 { | ||
|
||
@Test | ||
public void testCase() { | ||
String word1 = "horse"; | ||
String word2 = "ros"; | ||
int minDistance = 3; | ||
Assert.assertEquals(minDistance, minDistance(word1, word2)); | ||
|
||
word1 = "intention"; | ||
word2 = "execution"; | ||
minDistance = 5; | ||
Assert.assertEquals(minDistance, minDistance(word1, word2)); | ||
|
||
} | ||
|
||
/** | ||
* 空间优化 | ||
*/ | ||
public int minDistance(String word1, String word2) { | ||
int l1 = word1.length(); | ||
int l2 = word2.length(); | ||
|
||
if (l1 == 0) { | ||
return l2; | ||
} | ||
|
||
if (l2 == 0) { | ||
return l1; | ||
} | ||
|
||
int dp_i_1 = 1; | ||
int dp_j_1 = 1; | ||
int dp_i_1_j_1 = 0; | ||
int dp_i_j = 0; | ||
|
||
for (int i = 1; i <= l1; i++) { | ||
for (int j = 1; j <= l2; j++) { | ||
if (word1.charAt(i-1) == word2.charAt(j-1)) { | ||
dp_i_j = dp_i_1_j_1; | ||
// todo 相邻位置的变化 | ||
|
||
} else { | ||
dp_i_j = Math.min(dp_i_1 + 1, Math.min(dp_j_1 + 1, dp_i_1_j_1 + 1)); | ||
// todo 相邻位置的变化 | ||
|
||
} | ||
} | ||
} | ||
|
||
return dp_i_j; | ||
} | ||
|
||
/** | ||
* 动态规划 | ||
*/ | ||
public int minDistance_normal(String word1, String word2) { | ||
int l1 = word1.length(); | ||
int l2 = word2.length(); | ||
|
||
// dp[i][j]: w1[0...i-1] 与 w2[0...j-1] 的最短编辑距离 | ||
int[][] dp = new int[l1+1][l2+1]; | ||
|
||
for (int i = 0; i <= l1; i++) { | ||
dp[i][0] = i; | ||
} | ||
|
||
for (int j = 0; j <= l2; j++) { | ||
dp[0][j] = j; | ||
} | ||
|
||
for (int i = 1; i <= l1; i++) { | ||
for (int j = 1; j <= l2; j++) { | ||
if (word1.charAt(i-1) == word2.charAt(j-1)) { | ||
dp[i][j] = dp[i-1][j-1]; | ||
} else { | ||
dp[i][j] = min( | ||
dp[i][j - 1] + 1, // word2的 j 往前移动1位:word1新增一个字符 | ||
dp[i - 1][j] + 1, // word1的 i 往前移动1位:word1直接删除一个字符 | ||
dp[i - 1][j - 1] + 1 // word1 和 word2 一起移动,代表直接替换字符 | ||
); | ||
} | ||
} | ||
} | ||
|
||
return dp[l1][l2]; | ||
} | ||
|
||
private int min(int a, int b, int c) { | ||
return Math.min(a, Math.min(b, c)); | ||
} | ||
} |
96 changes: 96 additions & 0 deletions
96
src/main/java/algorithm_practice/LeetCode/code000/M039_组合总和.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package algorithm_practice.LeetCode.code000; | ||
|
||
import com.google.common.collect.Lists; | ||
import org.junit.Assert; | ||
import org.junit.Test; | ||
|
||
import java.util.*; | ||
|
||
/* | ||
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 | ||
candidates 中的数字可以无限制重复被选取。 | ||
说明: | ||
所有数字(包括 target)都是正整数。 | ||
解集不能包含重复的组合。 | ||
示例 1: | ||
输入:candidates = [2,3,6,7], target = 7, | ||
所求解集为: | ||
[ | ||
[7], | ||
[2,2,3] | ||
] | ||
示例 2: | ||
输入:candidates = [2,3,5], target = 8, | ||
所求解集为: | ||
[ | ||
[2,2,2,2], | ||
[2,3,3], | ||
[3,5] | ||
] | ||
提示: | ||
1 <= candidates.length <= 30 | ||
1 <= candidates[i] <= 200 | ||
candidate 中的每个元素都是独一无二的。 | ||
1 <= target <= 500 | ||
来源:力扣(LeetCode) | ||
链接:https://leetcode-cn.com/problems/combination-sum | ||
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 | ||
*/ | ||
public class M039_组合总和 { | ||
|
||
@Test | ||
public void testCase() { | ||
int[] candidates = new int[]{2,3,6,7}; | ||
int target = 7; | ||
List<List<Integer>> excepted = Lists.newArrayList( | ||
Lists.newArrayList(2,2,3), | ||
Lists.newArrayList(7)); | ||
Assert.assertEquals(excepted, combinationSum(candidates, target)); | ||
|
||
candidates = new int[]{2,3,5}; | ||
target = 8; | ||
excepted = Lists.newArrayList( | ||
Lists.newArrayList(2,2,2,2), | ||
Lists.newArrayList(2,3,3), | ||
Lists.newArrayList(3,5)); | ||
Assert.assertEquals(excepted, combinationSum(candidates, target)); | ||
|
||
} | ||
|
||
public List<List<Integer>> combinationSum(int[] candidates, int target) { | ||
List<List<Integer>> res = new ArrayList<>(); | ||
Deque<Integer> path = new LinkedList<>(); | ||
|
||
dfs(res, path, 0, candidates.length, candidates, target); | ||
return res; | ||
} | ||
|
||
private void dfs(List<List<Integer>> res, Deque<Integer> path, int begin, int end, int[] candidates, int target) { | ||
if (target < 0) { | ||
return; | ||
} | ||
|
||
if (target == 0) { | ||
res.add(new ArrayList<>(path)); | ||
} | ||
|
||
for (int i = begin; i < end; i++) { | ||
path.addLast(candidates[i]); | ||
|
||
dfs(res, path, i, end, candidates, target - candidates[i]); | ||
|
||
path.removeLast(); | ||
} | ||
} | ||
|
||
} |
133 changes: 133 additions & 0 deletions
133
src/main/java/algorithm_practice/LeetCode/code000/M040_组合总和2.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
package algorithm_practice.LeetCode.code000; | ||
|
||
import com.google.common.collect.Lists; | ||
import org.junit.Assert; | ||
import org.junit.Test; | ||
|
||
import java.util.*; | ||
import java.util.stream.Collectors; | ||
|
||
/* | ||
给定一个数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。 | ||
candidates 中的每个数字在每个组合中只能使用一次。 | ||
说明: | ||
所有数字(包括目标数)都是正整数。 | ||
解集不能包含重复的组合。 | ||
示例 1: | ||
输入: candidates = [10,1,2,7,6,1,5], target = 8, | ||
所求解集为: | ||
[ | ||
[1, 7], | ||
[1, 2, 5], | ||
[2, 6], | ||
[1, 1, 6] | ||
] | ||
示例 2: | ||
输入: candidates = [2,5,2,1,2], target = 5, | ||
所求解集为: | ||
[ | ||
[1,2,2], | ||
[5] | ||
] | ||
来源:力扣(LeetCode) | ||
链接:https://leetcode-cn.com/problems/combination-sum-ii | ||
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 | ||
*/ | ||
public class M040_组合总和2 { | ||
|
||
@Test | ||
public void testCase() { | ||
int[] candidates = new int[]{10,1,2,7,6,1,5}; | ||
int target = 8; | ||
List<List<Integer>> excepted = Lists.newArrayList( | ||
Lists.newArrayList(1, 2, 5), | ||
Lists.newArrayList(1,7), | ||
Lists.newArrayList(2, 6), | ||
Lists.newArrayList(1, 1, 6)); | ||
Assert.assertEquals(excepted, combinationSum2(candidates, target)); | ||
|
||
candidates = new int[]{2,5,2,1,2}; | ||
target = 5; | ||
excepted = Lists.newArrayList( | ||
Lists.newArrayList(1,2,2), | ||
Lists.newArrayList(5)); | ||
Assert.assertEquals(excepted, combinationSum2(candidates, target)); | ||
|
||
} | ||
|
||
public List<List<Integer>> combinationSum2(int[] candidates, int target) { | ||
List<List<Integer>> res = new ArrayList<>(); | ||
Deque<Integer> path = new LinkedList<>(); | ||
|
||
// 先排序,为了方便后面好判断是否真正只用了1次 candidates 里面的数字 | ||
Arrays.sort(candidates); | ||
|
||
dfs(res, path, 0, candidates.length, candidates, target); | ||
return res; | ||
} | ||
|
||
private void dfs(List<List<Integer>> res, Deque<Integer> path, int begin, int end, int[] candidates, int target) { | ||
if (target < 0) { | ||
return; | ||
} | ||
|
||
if (target == 0) { | ||
res.add(new ArrayList<>(path)); | ||
} | ||
|
||
for (int i = begin; i < end; i++) { | ||
|
||
// candidates[i] 不是begin位置的第一个数字 | ||
// 且 上一个candidates[i-1] 如果与当前的 candidates[i]相等,说明与同一层的选择重复,需剪枝。 | ||
if (i>begin && candidates[i-1] == candidates[i]) { | ||
continue; | ||
} | ||
|
||
path.addLast(candidates[i]); | ||
dfs(res, path, i+1, end, candidates, target-candidates[i]); | ||
path.removeLast(); | ||
} | ||
|
||
} | ||
|
||
/** | ||
* 耗时有点高。。 | ||
* 每次都有重新遍历 res,重新排序。判断是否contains | ||
*/ | ||
private void dfs_V1(List<List<Integer>> res, Deque<Integer> path, int begin, int end, int[] candidates, int target) { | ||
if (target < 0) { | ||
return; | ||
} | ||
|
||
if (target == 0 && !contains(res, path)) { | ||
res.add(new ArrayList<>(path)); | ||
} | ||
|
||
for (int i = begin; i < end; i++) { | ||
|
||
path.addLast(candidates[i]); | ||
|
||
dfs_V1(res, path, i+1, end, candidates, target - candidates[i]); | ||
|
||
path.removeLast(); | ||
} | ||
} | ||
|
||
private boolean contains(List<List<Integer>> res, Deque<Integer> path) { | ||
List<List<Integer>> sortedRes = new ArrayList<>(); | ||
for (List<Integer> oldPath : res) { | ||
sortedRes.add(oldPath.stream().sorted().collect(Collectors.toList())); | ||
} | ||
|
||
// res = sortedRes; | ||
return sortedRes.contains(path.stream().sorted().collect(Collectors.toList())); | ||
} | ||
|
||
} |
Oops, something went wrong.