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 }
  • 相关阅读:
    ASP.NET 5 Web Api 集成测试
    EF 7.0 Beta8 实现简单Unit Of Work 模式
    C#与闭包(closure)学习笔记
    异步初探
    BUBI架构之旅【目录】
    【第2期】如何将NameNode和SecondaryNameNode分开不同节点
    【第1期】使用Docker虚拟化技术搭设Hadoop环境
    【第3期】Linux安装数据库oracle 11g
    【第2期】vsftpd的安装与使用
    【第1期】安装Linux服务器(DB主机与ETL主机)
  • 原文地址:https://www.cnblogs.com/liujinhong/p/6115261.html
Copyright © 2011-2022 走看看