一、題目描述
今天下午面試老虎證券,被問到這題,當時腦子有點蒙,代碼沒寫出來。這題的意思就是給你一個數組,讓你計算元素的和,但是這些元素都不能相鄰,求最大的和。其實這題很常見,在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); }