动态规划:打劫房间

    给定一个数组,表示一条街上每个房间的金钱数。盗贼抢劫这条街时,如果抢劫了相邻的两个房间,则会触发报警。问盗贼最多能抢到多少钱。

    分析:对于每一个房间,有两个选择:抢劫或者不抢劫。如果不抢,前一个房间可以抢也可以不抢,取两者的最大值就是当前的最大值;如果抢,那么前一个房间则不可以抢,得到的钱数是不抢前一个房间得到的钱数加上抢劫当前房间得到的钱数。用一个二维数组记录访问每一个房间时可以得到的钱数,其中,money[i][0]表示不抢当前房间可以得到的钱数,money[i][1]表示抢劫当前房间可以得到的钱数。

    public int rob(int[] nums) {
        if(nums.length == 0)
            return 0;
        int[][] money = new int[nums.length][2];
        money[0][0] = 0;
        money[0][1] = nums[0];
        for(int i = 1; i < nums.length; i++){
            money[i][0] = Math.max(money[i - 1][0], money[i - 1][1]); //不抢当前房间,前一个可以抢也可以不抢,取最大值
            money[i][1] = money[i - 1][0] + nums[i];
        }
        return Math.max(money[nums.length - 1][0], money[nums.length - 1][1]);
    }

    进阶:如果最后一个房间和第一个房间相邻,组成一个环形。

    想办法把这个“环”打断:如果打劫第一个房间,那么最后一个房间不可以打劫,此时按照上面的算法,只计算到n-1;如果不打劫第一个房间,那么可以考虑最后一个房间,按照上面的算法从第2个房间开始计算,到第n个房间。然后再取两者的最大值。

    public int rob(int[] nums, int low, int high) {
        int include = 0, exclude = 0;
        for(int i = low; i <= high; i++){
            int preExclude = exclude;
            exclude = Math.max(exclude, include);
            include = preExclude + nums[i];
        }
        return Math.max(exclude, include);
    }
    public int rob(int[] nums){
        if(nums.length == 1)
            return nums[0];
        return Math.max(rob(nums, 0, nums.length - 2), rob(nums, 1, nums.length - 1));
    }

你可能感兴趣的:(动态规划)