面对动态规划专业术语:状态转移方程,最优子结构,边界。很少有人看懂。
实际上动态规划有一条演进路线:暴力递归--》记忆化搜索--》二维表推进(动态规划)。
从打家劫舍这道题入手:
难度中等2139收藏分享切换为英文接收动态反馈
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 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 。
提示:
1 <= nums.length <= 100
0 <= nums[i] <= 400
1.暴力递归法:
class Solution { public int rob(int[] nums) { return dfs(0, nums); } public int dfs(int curIndex, int[] nums) { if (curIndex >= nums.length) { return 0; } return Math.max(nums[curIndex] + dfs(curIndex + 2, nums), dfs(curIndex + 1, nums)); } }
这种方法对于数据量小的情况没问题。当数据量比较大时,出现超过时间限制。怎么回事?因为递归里有很多重复的计算。演进成下一步:记忆化搜索:
2.记忆化搜索:
class Solution { public int rob(int[] nums) { int[] arr = new int[nums.length]; for (int i = 0; i < arr.length; i++) { arr[i] = -1; } return dfs(0, nums, arr); } public int dfs(int curIndex, int[] nums,int[] arr) { if (curIndex >= nums.length) { return 0; } if (arr[curIndex] == -1) { int p1 = nums[curIndex] + dfs(curIndex + 2, nums, arr); int p2 = dfs(curIndex + 1, nums, arr); arr[curIndex] = Math.max(p1, p2); } return arr[curIndex]; } }
演进成下一步:动态规则:
3.动态规则
class Solution { public int rob(int[] nums) { int[][] arr = new int[nums.length + 1][nums.length + 1]; arr[0][0] = 0; arr[1][1] = nums[0]; for (int i = 2; i < arr.length; i++) { //上一个为选的 和 上上个和当前树 比较 arr[i][i] = Math.max(arr[i-2][i-2] + nums[i-1], arr[i-1][i-1]); } return arr[nums.length][nums.length]; } }