数组不相邻元素之和的最大值

一、题目描述

今天下午面试老虎证券,被问到这题,当时脑子有点蒙,代码没写出来。这题的意思就是给你一个数组,让你计算元素的和,但是这些元素都不能相邻,求最大的和。其实这题很常见,在leetcode上面也有,但是原题是这样的:

假设你是一个专业的窃贼,准备沿着一条街打劫房屋。每个房子都存放着特定金额的钱。你面临的唯一约束条件是:相邻的房子装着相互联系的防盗系统,且 当相邻的两个房子同一天被打劫时,该系统会自动报警。给定一个非负整数列表,表示每个房子中存放的钱, 算一算,如果今晚去打劫,你最多可以得到多少钱 在不触动报警装置的情况下。

例如:
数组arr为[1, 3, 5, 4, 9],那么结果为 1 + 5 + 9 = 15,再例如数组arr为[5, 1, 3, 11, 7],那么结果为5 + 11 = 16,从这两个例子可以看出,单纯的计算奇数位的和或者偶数位的和得到的结果未必是最大的。
解题思路
定义一个数组p,p[i] 代表从第0到第i个房屋,打劫第i个房屋为止所获得金钱总额,也就是说第i个房屋要打劫,而p[i]肯定等于arr[i] + p[i-2]或者arr[i] + p[i-3]的最大值,因为相邻的房屋不能打劫,所以p[i-1]不能算。最后我们只要计算p[arr.length-1]和p[arr.length-2]哪个大就行了。p[arr.length-3]肯定不是最大的,因为p[arr.length-3] + arr[arr.length-1]肯定比p[arr.length-3]大。

二、代码实现

public static int getMaxSum(int[] arr) {
        if(arr.length == 0) return 0;
        if(arr.length == 1) return arr[0];
        if(arr.length == 2) return Math.max(arr[0], arr[1]);
        if(arr.length == 3) return Math.max(arr[1], arr[0] + arr[2]);
        int[] p = new int[arr.length];
        p[0] = arr[0];
        p[1] = arr[1];
        p[2] = arr[0] + arr[2];
        for(int i = 3; i < arr.length; i++) {
            p[i] = arr[i] + Math.max(p[i-2], p[i-3]);
        }
        return Math.max(p[arr.length-1],p[arr.length-2]);
    }

其实这题还能优化为o(1)的空间,从上面的代码分析,在计算打劫第i个房屋的收益的时候,其实只是和打劫前面3个房屋的收益有关,我们完全可以定义4个变量来表示。

public static int getMaxSum2(int[] arr) {
        if(arr.length == 0) return 0;
        if(arr.length == 1) return arr[0];
        if(arr.length == 2) return Math.max(arr[0], arr[1]);
        if(arr.length == 3) return Math.max(arr[1], arr[0] + arr[2]);
        int m0 = arr[0];
        int m1 = arr[1];
        int m2 = arr[0] + arr[2];
        int m3 = 0;
        for(int i = 3; i < arr.length; i++) {
            m3 = arr[i] + Math.max(m0, m1);
            m0 = m1;
            m1 = m2;
            m2 = m3;
        }
        return Math.max(m3, m2);
    }

 

posted @ 2018-08-19 17:22  neu_张康  阅读(4017)  评论(0编辑  收藏  举报