从零学算法

198.你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 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 号房屋为止的最高金额,偷到 2 号房屋为止的最高金额…, 那么就有 f[i] 为偷到最后一个房屋为 i 时的最高金额(不一定就偷了 i 房屋,只是范围到 i 为止),接着找关联性,注意限制条件不能偷连续的房屋,首先 f[0] ,只能偷房屋 1,就直接为 nums[0] ,接着 f[1] 开始有说法了,两个房屋,我要么偷了前一个,这个不偷了,要么前一个没偷,我偷这个,两者我取最大值,所以为 max(f[0],nums[1]), f[2] ,同理 f[2] 也是两种可能,如果我偷了前一个房屋,那么我这个房屋是肯定不能偷了,也就是说我只能是 f[2-1],而如果我前一天没偷,那么我今天必偷无疑,也就是 f[2-2] + nums[2],两者之中我取最大的可能性即可,以此类推,这也就得到了状态转移方程和初始值。为了方便我定义数组时长度加了 1,表示第一天的时候,前一天(逻辑上不存在,所以正好为 0)不偷的金额为 0,偷则为 nums[0]。
  •   public int rob(int[] nums) {
          int m = nums.length;
          int[] f = new int[m+1];
          f[1] = nums[0];
          for(int i=2; i<=m; i++){
              f[i] = Math.max(f[i-1],f[i-2]+nums[i-1]);
          }
          return f[m];
      }
    
  • 由于我们只需要知道前一天偷或不偷,所以定义两个变量滚动更新记录就足够了,不需要数组
  •   int m = nums.length;
      int x1=0,x2=nums[0];
      for(int i=2; i<=m; i++){
          int temp = Math.max(x2,x1+nums[i-1]);
          x1 = x2;
          x2 = temp;
      }
      return Math.max(x1,x2);
    
  • 他人题解我就不看了

你可能感兴趣的:(算法学习,算法)