Skip to content

Commit

Permalink
动态规划 打家劫舍、不同路径
Browse files Browse the repository at this point in the history
  • Loading branch information
nibnait committed Oct 31, 2020
1 parent 9d4a2a9 commit 5e62ed3
Show file tree
Hide file tree
Showing 10 changed files with 714 additions and 20 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package algorithm_practice.LeetCode.code000;

import org.junit.Assert;
import org.junit.Test;

/*
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
问总共有多少条不同的路径?
例如,上图是一个7 x 3 的网格。有多少可能的路径?
 
示例 1:
输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向右 -> 向下
2. 向右 -> 向下 -> 向右
3. 向下 -> 向右 -> 向右
示例 2:
输入: m = 7, n = 3
输出: 28
 
提示:
1 <= m, n <= 100
题目数据保证答案小于等于 2 * 10 ^ 9
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-paths
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class M062_不同路径 {
@Test
public void testCase() {
int m = 3;
int n = 2;
int excepted = 3;
Assert.assertEquals(excepted, uniquePaths(m, n));

m = 7;
n = 3;
excepted = 28;
Assert.assertEquals(excepted, uniquePaths(m, n));

m = 3;
n = 7;
excepted = 28;
Assert.assertEquals(excepted, uniquePaths(m, n));

}

public int uniquePaths(int m, int n) {

int[][] dp = new int[m][n];

for (int i = 0; i < m; i++) {
dp[i][0] = 1;
}

for (int i = 0; i < n; i++) {
dp[0][i] = 1;
}

for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}

return dp[m-1][n-1];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package algorithm_practice.LeetCode.code000;

import org.junit.Assert;
import org.junit.Test;

/*
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?
网格中的障碍物和空位置分别用 1 和 0 来表示。
说明:m 和 n 的值均不超过 100。
示例 1:
输入:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
输出: 2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-paths-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class M063_不同路径2 {
@Test
public void testCase() {
int[][] obstacleGrid = new int[][]{
{0,0,0},
{0,1,0},
{0,0,0}};
int expected = 2;
Assert.assertEquals(expected, uniquePathsWithObstacles(obstacleGrid));

obstacleGrid = new int[][]{
{1,0}};
expected = 0;
Assert.assertEquals(expected, uniquePathsWithObstacles(obstacleGrid));

obstacleGrid = new int[][]{
{0,0},
{0,1}};
expected = 0;
Assert.assertEquals(expected, uniquePathsWithObstacles(obstacleGrid));

obstacleGrid = new int[][]{
{0,0,0,0,0},
{0,0,0,0,1},
{0,0,0,1,0},
{0,0,1,0,0}};
expected = 0;
Assert.assertEquals(expected, uniquePathsWithObstacles(obstacleGrid));

}

public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
if (m == 0) {
return 0;
}

int n = obstacleGrid[0].length;
if (obstacleGrid[m-1][n-1] == 1) {
return 0;
}

int[][] dp = new int[m][n];

boolean blockFlag = false;
for (int i = 0; i < m; i++) {
if (obstacleGrid[i][0] == 1 || blockFlag) {
dp[i][0] = 0;
blockFlag = true;
} else {
dp[i][0] = 1;
}
}

blockFlag = false;
for (int i = 0; i < n; i++) {
if (obstacleGrid[0][i] == 1 || blockFlag) {
dp[0][i] = 0;
blockFlag = true;
} else {
dp[0][i] = 1;
}
}

for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (obstacleGrid[i][j] == 1){
dp[i][j] = 0;
} else {
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
}

return dp[m-1][n-1];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package algorithm_practice.LeetCode.code100;

import org.junit.Assert;
import org.junit.Test;

/*
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
 
示例 1:
输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
  偷窃到的最高金额 = 1 + 3 = 4 。
示例 2:
输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
  偷窃到的最高金额 = 2 + 9 + 1 = 12 。
 
提示:
0 <= nums.length <= 100
0 <= nums[i] <= 400
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/house-robber
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class E198_打家劫舍 {
@Test
public void testCase() {
int[] nums = new int[]{1,2,3,1};
int excepted = 4;
Assert.assertEquals(excepted, rob(nums));

nums = new int[]{2,7,9,3,1};
excepted = 12;
Assert.assertEquals(excepted, rob(nums));

}

public int rob(int[] nums) {
if (nums.length == 0) {
return 0;
}

if (nums.length == 1) {
return nums[0];
}

// dp[i]: nums[0...i] 偷窃到的最高金额
int[] dp = new int[nums.length];
dp[0] = nums[0];
dp[1] = Math.max(nums[0], nums[1]);

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

return dp[nums.length-1];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package algorithm_practice.LeetCode.code200;

import org.junit.Assert;
import org.junit.Test;

/*
你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,能够偷窃到的最高金额。
 
示例 1:
输入:nums = [2,3,2]
输出:3
解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。
示例 2:
输入:nums = [1,2,3,1]
输出:4
解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
  偷窃到的最高金额 = 1 + 3 = 4 。
示例 3:
输入:nums = [0]
输出:0
 
提示:
1 <= nums.length <= 100
0 <= nums[i] <= 1000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/house-robber-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class M213_打家劫舍2 {
@Test
public void testCase() {
int[] nums = new int[]{1, 2, 3, 1};
int excepted = 4;
Assert.assertEquals(excepted, rob(nums));

nums = new int[]{2, 3, 2};
excepted = 3;
Assert.assertEquals(excepted, rob(nums));

nums = new int[]{0};
excepted = 0;
Assert.assertEquals(excepted, rob(nums));

nums = new int[]{1, 1};
excepted = 1;
Assert.assertEquals(excepted, rob(nums));

nums = new int[]{200, 3, 140, 20, 10};
excepted = 340;
Assert.assertEquals(excepted, rob(nums));

nums = new int[]{1, 3, 1, 3, 100};
excepted = 103;
Assert.assertEquals(excepted, rob(nums));

}

public int rob(int[] nums) {
int length = nums.length;
if (length == 1) {
return nums[0];
}
if (length == 2) {
return Math.max(nums[0],nums[1]);
}

return Math.max(rob(nums, 0, length - 2),
rob(nums, 1, length - 1));
}

private int rob(int[] nums, int begin, int end) {
int[] dp = new int[nums.length];
dp[begin] = nums[begin];
dp[begin+1] = Math.max(nums[begin], nums[begin+1]);

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

return dp[end];
}

}
Loading

0 comments on commit 5e62ed3

Please sign in to comment.