求一个非负整数数组中不相邻元素之和的最大值

本文解析了LeetCode上的经典动态规划题目——打家劫舍问题,并提供了两种解题思路:递归法与迭代法。此外,还进一步讨论了当房屋呈环状分布时的解决方案。

该题来自leetcode,原题如下:

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.

这是一道DP问题,首先该题符合“最优子结构”,该题的递推公式:dp(n) = max(dp(n-1), dp(n-2) + nums[n]),另外根据“重叠子问题”原则,如果仅仅使用简单的递归求解,则会有严重的重复计算,时间复杂度成指数增长,所以要额外开销一个数组来存储已经计算出来的dp(i)值。

方法一、递归法

    public int dpRob(int[] nums, int n, int[] array) {
        if (n < 0)
            return 0;if(array[n] == -1)
            array[n] = Math.max(dpRob(nums, n-1, array), dpRob(nums, n-2, array) + nums[n]);
        return array[n];
    }
    public int rob(int[] nums) {
        int[] array = new int[nums.length];
        Arrays.fill(array, -1); //此处数组元素要初始化为负数
        return dpRob(nums, nums.length-1, array);
    }

方法二:迭代法

    public int rob(int[] nums) {
        if(nums.length == 0) return 0;
        if(nums.length == 1) return nums[0];
        int[] dp = new int[nums.length];
        dp[0] = nums[0]; //初始化值
        dp[1] = Math.max(nums[0], nums[1]); //初始化值
        for(int i = 2; i < nums.length; i++) {
            dp[i] = Math.max(dp[i-2] + nums[i], dp[i-1]);
        }
        return dp[nums.length-1];
    }        

 进阶:

若这些房子成环形排列,即第一个房子和最后一个房子相邻,求此时和的最大值。

分析:可以把原数组nums分成两个子数组,转化为线性排列求解,一个数组nums1下标是从0到n-2,另一个数组nums2下标是从1到n-1,两个子数组求解结果中较大的结果为该题的解。

Java递归代码如下:

    int dpRob(int[] nums, int n, int[] array) {
        if (n < 0) 
            return 0;
        if(array[n] == -1)
            array[n] = Math.max(dpRob(nums, n-1, array), dpRob(nums, n-2, array) + nums[n]);
        return array[n];
    }
    public int rob(int[] nums) {
        if (nums.length == 0)
            return 0;
        if (nums.length == 1)
            return nums[0];
        int[] nums1 = new int[nums.length-1];
        int[] nums2 = new int[nums.length-1];
        System.arraycopy(nums, 0, nums1, 0, nums.length-1);
        System.arraycopy(nums, 1, nums2, 0, nums.length-1);
        int[] array = new int[nums.length];
        Arrays.fill(array, -1);
        int result1 = dpRob(nums1, nums1.length-1, array);
        Arrays.fill(array, -1);
        int result2 = dpRob(nums2, nums2.length-1, array);
        return Math.max(result1, result2);
    }

 

转载于:https://www.cnblogs.com/lasclocker/p/4890151.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值