Skip to content

Commit 5e62ed3

Browse files
author
nibnait
committed
动态规划 打家劫舍、不同路径
1 parent 9d4a2a9 commit 5e62ed3

10 files changed

Lines changed: 714 additions & 20 deletions

File tree

src/main/java/algorithm_practice/Coding_Interview_Guide_2ndEdition/Chapter_04_递归和动态规划/P04_换钱的最少货币数.java

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package algorithm_practice.LeetCode.code000;
2+
3+
import org.junit.Assert;
4+
import org.junit.Test;
5+
6+
/*
7+
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
8+
9+
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
10+
11+
问总共有多少条不同的路径?
12+
13+
14+
15+
例如,上图是一个7 x 3 的网格。有多少可能的路径?
16+
17+
 
18+
19+
示例 1:
20+
21+
输入: m = 3, n = 2
22+
输出: 3
23+
解释:
24+
从左上角开始,总共有 3 条路径可以到达右下角。
25+
1. 向右 -> 向右 -> 向下
26+
2. 向右 -> 向下 -> 向右
27+
3. 向下 -> 向右 -> 向右
28+
示例 2:
29+
30+
输入: m = 7, n = 3
31+
输出: 28
32+
 
33+
34+
提示:
35+
36+
1 <= m, n <= 100
37+
题目数据保证答案小于等于 2 * 10 ^ 9
38+
39+
40+
来源:力扣(LeetCode)
41+
链接:https://leetcode-cn.com/problems/unique-paths
42+
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
43+
*/
44+
public class M062_不同路径 {
45+
@Test
46+
public void testCase() {
47+
int m = 3;
48+
int n = 2;
49+
int excepted = 3;
50+
Assert.assertEquals(excepted, uniquePaths(m, n));
51+
52+
m = 7;
53+
n = 3;
54+
excepted = 28;
55+
Assert.assertEquals(excepted, uniquePaths(m, n));
56+
57+
m = 3;
58+
n = 7;
59+
excepted = 28;
60+
Assert.assertEquals(excepted, uniquePaths(m, n));
61+
62+
}
63+
64+
public int uniquePaths(int m, int n) {
65+
66+
int[][] dp = new int[m][n];
67+
68+
for (int i = 0; i < m; i++) {
69+
dp[i][0] = 1;
70+
}
71+
72+
for (int i = 0; i < n; i++) {
73+
dp[0][i] = 1;
74+
}
75+
76+
for (int i = 1; i < m; i++) {
77+
for (int j = 1; j < n; j++) {
78+
dp[i][j] = dp[i-1][j] + dp[i][j-1];
79+
}
80+
}
81+
82+
return dp[m-1][n-1];
83+
}
84+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package algorithm_practice.LeetCode.code000;
2+
3+
import org.junit.Assert;
4+
import org.junit.Test;
5+
6+
/*
7+
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
8+
9+
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
10+
11+
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
12+
13+
14+
15+
网格中的障碍物和空位置分别用 1 和 0 来表示。
16+
17+
说明:m 和 n 的值均不超过 100。
18+
19+
示例 1:
20+
21+
输入:
22+
[
23+
  [0,0,0],
24+
  [0,1,0],
25+
  [0,0,0]
26+
]
27+
输出: 2
28+
解释:
29+
3x3 网格的正中间有一个障碍物。
30+
从左上角到右下角一共有 2 条不同的路径:
31+
1. 向右 -> 向右 -> 向下 -> 向下
32+
2. 向下 -> 向下 -> 向右 -> 向右
33+
34+
35+
来源:力扣(LeetCode)
36+
链接:https://leetcode-cn.com/problems/unique-paths-ii
37+
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
38+
*/
39+
public class M063_不同路径2 {
40+
@Test
41+
public void testCase() {
42+
int[][] obstacleGrid = new int[][]{
43+
{0,0,0},
44+
{0,1,0},
45+
{0,0,0}};
46+
int expected = 2;
47+
Assert.assertEquals(expected, uniquePathsWithObstacles(obstacleGrid));
48+
49+
obstacleGrid = new int[][]{
50+
{1,0}};
51+
expected = 0;
52+
Assert.assertEquals(expected, uniquePathsWithObstacles(obstacleGrid));
53+
54+
obstacleGrid = new int[][]{
55+
{0,0},
56+
{0,1}};
57+
expected = 0;
58+
Assert.assertEquals(expected, uniquePathsWithObstacles(obstacleGrid));
59+
60+
obstacleGrid = new int[][]{
61+
{0,0,0,0,0},
62+
{0,0,0,0,1},
63+
{0,0,0,1,0},
64+
{0,0,1,0,0}};
65+
expected = 0;
66+
Assert.assertEquals(expected, uniquePathsWithObstacles(obstacleGrid));
67+
68+
}
69+
70+
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
71+
int m = obstacleGrid.length;
72+
if (m == 0) {
73+
return 0;
74+
}
75+
76+
int n = obstacleGrid[0].length;
77+
if (obstacleGrid[m-1][n-1] == 1) {
78+
return 0;
79+
}
80+
81+
int[][] dp = new int[m][n];
82+
83+
boolean blockFlag = false;
84+
for (int i = 0; i < m; i++) {
85+
if (obstacleGrid[i][0] == 1 || blockFlag) {
86+
dp[i][0] = 0;
87+
blockFlag = true;
88+
} else {
89+
dp[i][0] = 1;
90+
}
91+
}
92+
93+
blockFlag = false;
94+
for (int i = 0; i < n; i++) {
95+
if (obstacleGrid[0][i] == 1 || blockFlag) {
96+
dp[0][i] = 0;
97+
blockFlag = true;
98+
} else {
99+
dp[0][i] = 1;
100+
}
101+
}
102+
103+
for (int i = 1; i < m; i++) {
104+
for (int j = 1; j < n; j++) {
105+
if (obstacleGrid[i][j] == 1){
106+
dp[i][j] = 0;
107+
} else {
108+
dp[i][j] = dp[i-1][j] + dp[i][j-1];
109+
}
110+
}
111+
}
112+
113+
return dp[m-1][n-1];
114+
}
115+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package algorithm_practice.LeetCode.code100;
2+
3+
import org.junit.Assert;
4+
import org.junit.Test;
5+
6+
/*
7+
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
8+
9+
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
10+
11+
 
12+
13+
示例 1:
14+
15+
输入:[1,2,3,1]
16+
输出:4
17+
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
18+
  偷窃到的最高金额 = 1 + 3 = 4 。
19+
示例 2:
20+
21+
输入:[2,7,9,3,1]
22+
输出:12
23+
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
24+
  偷窃到的最高金额 = 2 + 9 + 1 = 12 。
25+
 
26+
27+
提示:
28+
29+
0 <= nums.length <= 100
30+
0 <= nums[i] <= 400
31+
32+
33+
来源:力扣(LeetCode)
34+
链接:https://leetcode-cn.com/problems/house-robber
35+
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
36+
*/
37+
public class E198_打家劫舍 {
38+
@Test
39+
public void testCase() {
40+
int[] nums = new int[]{1,2,3,1};
41+
int excepted = 4;
42+
Assert.assertEquals(excepted, rob(nums));
43+
44+
nums = new int[]{2,7,9,3,1};
45+
excepted = 12;
46+
Assert.assertEquals(excepted, rob(nums));
47+
48+
}
49+
50+
public int rob(int[] nums) {
51+
if (nums.length == 0) {
52+
return 0;
53+
}
54+
55+
if (nums.length == 1) {
56+
return nums[0];
57+
}
58+
59+
// dp[i]: nums[0...i] 偷窃到的最高金额
60+
int[] dp = new int[nums.length];
61+
dp[0] = nums[0];
62+
dp[1] = Math.max(nums[0], nums[1]);
63+
64+
for (int i = 2; i < nums.length; i++) {
65+
dp[i] = Math.max(dp[i-1], dp[i-2] + nums[i]);
66+
}
67+
68+
return dp[nums.length-1];
69+
}
70+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
package algorithm_practice.LeetCode.code200;
2+
3+
import org.junit.Assert;
4+
import org.junit.Test;
5+
6+
/*
7+
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
8+
9+
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,能够偷窃到的最高金额。
10+
11+
 
12+
13+
示例 1:
14+
15+
输入:nums = [2,3,2]
16+
输出:3
17+
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
18+
示例 2:
19+
20+
输入:nums = [1,2,3,1]
21+
输出:4
22+
解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
23+
  偷窃到的最高金额 = 1 + 3 = 4 。
24+
示例 3:
25+
26+
输入:nums = [0]
27+
输出:0
28+
 
29+
30+
提示:
31+
32+
1 <= nums.length <= 100
33+
0 <= nums[i] <= 1000
34+
35+
36+
来源:力扣(LeetCode)
37+
链接:https://leetcode-cn.com/problems/house-robber-ii
38+
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
39+
*/
40+
public class M213_打家劫舍2 {
41+
@Test
42+
public void testCase() {
43+
int[] nums = new int[]{1, 2, 3, 1};
44+
int excepted = 4;
45+
Assert.assertEquals(excepted, rob(nums));
46+
47+
nums = new int[]{2, 3, 2};
48+
excepted = 3;
49+
Assert.assertEquals(excepted, rob(nums));
50+
51+
nums = new int[]{0};
52+
excepted = 0;
53+
Assert.assertEquals(excepted, rob(nums));
54+
55+
nums = new int[]{1, 1};
56+
excepted = 1;
57+
Assert.assertEquals(excepted, rob(nums));
58+
59+
nums = new int[]{200, 3, 140, 20, 10};
60+
excepted = 340;
61+
Assert.assertEquals(excepted, rob(nums));
62+
63+
nums = new int[]{1, 3, 1, 3, 100};
64+
excepted = 103;
65+
Assert.assertEquals(excepted, rob(nums));
66+
67+
}
68+
69+
public int rob(int[] nums) {
70+
int length = nums.length;
71+
if (length == 1) {
72+
return nums[0];
73+
}
74+
if (length == 2) {
75+
return Math.max(nums[0],nums[1]);
76+
}
77+
78+
return Math.max(rob(nums, 0, length - 2),
79+
rob(nums, 1, length - 1));
80+
}
81+
82+
private int rob(int[] nums, int begin, int end) {
83+
int[] dp = new int[nums.length];
84+
dp[begin] = nums[begin];
85+
dp[begin+1] = Math.max(nums[begin], nums[begin+1]);
86+
87+
for (int i = begin+2; i <= end; i++) {
88+
dp[i] = Math.max(nums[i] + dp[i - 2], dp[i - 1]);
89+
}
90+
91+
return dp[end];
92+
}
93+
94+
}

0 commit comments

Comments
 (0)