zoukankan      html  css  js  c++  java
  • LeetCode 198. House Robber

    You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.

    Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

    Credits:
    Special thanks to @ifanchu for adding this problem and creating all test cases. Also thanks to @ts for adding additional test cases.

    【题目分析】

    这是一个很经典的动态规划的题目,意思是一个盗贼要偷盗一条街道上的店铺。唯一的限制就是不能同时偷盗连续的两家店铺,否则的话报警器就会被触发,求在不触发警报的情况下该盗贼可偷盗的最多金钱数。

    【思路】

    1. 用递归来解决

    盗贼遍历店铺,从当前店铺开始获取的最大收益 = max(偷盗当前店铺获取的最大收益, 不偷盗当前店铺获取的最大收益)

    代码如下:

     1 public class Solution {
     2     public int rob(int[] nums) {
     3         return robber(nums, 0);
     4     }
     5     
     6     public int robber(int[] nums, int start) {
     7         if(start > nums.length-1) return 0;
     8         if(start == nums.length-1) return nums[start];
     9         int result1 = 0, result2 = 0;
    10         result1 = nums[start] + robber(nums, start+2);
    11         result2 = robber(nums, start+1);
    12         
    13         return result1 > result2 ? result1 : result2;
    14     }
    15 }

    上面的代码时间复杂度较高。原因在于递归的时候一些中间的计算结果没有保存下来,导致多次计算已经计算后的结果。对上面的代码进行改进如下:

     1 public class Solution {
     2     public int rob(int[] nums) {
     3         int[] mark = new int[nums.length];
     4         for(int i = 0; i < nums.length; i++) {
     5             mark[i] = -1;
     6         }
     7         return robber(nums, mark, 0);
     8     }
     9     
    10     public int robber(int[] nums, int[] mark, int start) {
    11         if(start > nums.length-1) return 0;
    12         if(start == nums.length-1) return nums[start];
    13         int result1 = 0, result2 = 0;
    14         if(start+2 < nums.length && mark[start+2] > -1) {
    15             result1 = nums[start] + mark[start+2];
    16         } else {
    17             result1 = nums[start] + robber(nums, mark, start+2);
    18         }
    19         
    20         if(start+1 < nums.length && mark[start+1] > -1) {
    21             result2 = mark[start+1];
    22         } else {
    23             result2 = robber(nums, mark, start+1);
    24         }
    25         
    26         mark[start] = result1 > result2 ? result1 : result2;
    27         return mark[start];
    28     }
    29 }

    上面的代码用mark数组保存了已经计算过的最优值,递归过程中如果发现该值已经被计算过,则直接取出已经计算过的结果即可。

    递归表达式为:rob[start] = max(rob[start+1], nums[start] + rob[start+2])

    上面的代码太过冗余,优化后的代码如下:

     1 public class Solution {
     2     public int rob(int[] nums) {
     3         int len = nums.length;
     4         if(len == 0) return 0;
     5         if(len == 1) return nums[0];
     6         
     7         int[] mark = new int[len];
     8         mark[len-1] = nums[len-1];
     9         mark[len-2] = Math.max(nums[len-1], nums[len-2]);
    10         
    11         for(int i = len-3; i >= 0; i--) {
    12             mark[i] = Math.max(mark[i+1], nums[i] + mark[i+2]);
    13         }
    14         return mark[0];
    15     }
    16 }

    上面代码的空间复杂度为O(n),我们发现其实不必把已经计算过的所有信息保存下来,只要保存后两个记录即可,优化后的空间复杂度为O(1),代码如下:

     1 public class Solution {
     2     public int rob(int[] nums) {
     3         int len = nums.length;
     4         if(len == 0) return 0;
     5         if(len == 1) return nums[0];
     6         
     7         int post2 = nums[len-1];
     8         int post1 = Math.max(nums[len-2], nums[len-1]);
     9         
    10         for(int i = len-3; i >= 0; i--) {
    11             int temp = post1;
    12             post1 = Math.max(post1, nums[i] + post2);
    13             post2 = temp;
    14         }
    15         return post1;
    16     }
    17 }
  • 相关阅读:
    Django 2.0.1 官方文档翻译: 编写你的第一个 Django app,第四部分(Page 9)
    Django 2.0.1 官方文档翻译: 编写你的第一个 Django app,第一部分(Page 6)
    Django 2.0.1 官方文档翻译: 编写你的第一个 Django app,第二部分(Page 7)
    Django 2.0.1 官方文档翻译: 编写你的第一个 Django app,第三部分(Page 8)
    Django 2.0.1 官方文档翻译: 如何安装 django (Page 17)
    Django 2.0.1 官方文档翻译: 文档目录 (Page 1)
    Django 2.0.1 官方文档翻译: 快速安装向导 (Page5)
    如何画流程图
    centos7.x firewall简单使用
    cetos6配置用msmtp和mutt发邮件(阿里云)
  • 原文地址:https://www.cnblogs.com/liujinhong/p/6115261.html
Copyright © 2011-2022 走看看