Given an array nums
of integers, you can perform operations on the array.html
In each operation, you pick any nums[i]
and delete it to earn nums[i]
points. After, you must delete everyelement equal to nums[i] - 1
or nums[i] + 1
.java
You start with 0 points. Return the maximum number of points you can earn by applying such operations.數組
Example 1:app
Input: nums = [3, 4, 2] Output: 6 Explanation: Delete 4 to earn 4 points, consequently 3 is also deleted. Then, delete 2 to earn 2 points. 6 total points are earned.
Example 2:post
Input: nums = [2, 2, 3, 3, 3, 4] Output: 9 Explanation: Delete 3 to earn 3 points, deleting both 2's and the 4. Then, delete 3 again to earn 3 points, and 3 again to earn 3 points. 9 total points are earned.
Note:url
nums
is at most 20000
.nums[i]
is an integer in the range [1, 10000]
.
博主浪了整整一個聖誕假期,如今也該收收心了,2018了,今年對於博主是很關鍵的一年,有太多的事情要去作,各類小目標須要完成,還有夢想去追逐,又要開始努力啦~在博主停更的這一週半的時間內,收到了網友們的私信和留言催更,請你們放心,2018年博主會繼續堅持下去,繼續追趕進度,雖然一直都沒有徹底追上-.-|||,照LeetCode這出題速度,今年題號有望突破一千大關啊,感受碉堡了有木有,一塊兒爲了幸福而奮鬥吧~spa
好了,來作題吧。這道題給了咱們一個數組,每次讓咱們刪除一個數字,刪除的數字自己變爲了積分累積,而且要同時移除以前數的加1和減1的數,但此時移除的數字不累計積分,讓咱們求最多能得到多少積分。博主最開始嘗試的方法是積分大小來排列,先刪除大的數字,可是不對。因而乎,博主發現相同的數字能夠同時刪除,因而就是創建了每一個數字和其出現次數之間的映射,而後放到優先隊列裏,重寫排序方式comparator爲數字乘以其出現次數,先移除能產生最大積分的數字,但是仍是不對。其實這道題跟以前那道House Robber的本質是同樣的,那道題小偷不能偷相鄰的房子,這道題相鄰的數字不能累加積分,是否是一個道理?那麼對於每個數字,咱們都有兩個選擇,拿或者不拿。若是咱們拿了當前的數字,咱們就不能拿以前的數字(若是咱們從小往大遍歷就不須要考慮後面的數字),那麼當前的積分就是不拿前面的數字的積分加上當前數字之和。若是咱們不拿當前的數字,那麼對於前面的數字咱們既能夠拿也能夠不拿,因而當前的積分就是拿前面的數字的積分和不拿前面數字的積分中的較大值。這裏咱們用take和skip分別表示拿與不拿上一個數字,takei和skipi分別表示拿與不拿當前數字,每次更新完當前的takei和skipi時,也要更新take和skip,爲下一個數字作準備,最後只要返回take和skip中的較大值便可,參見代碼以下:code
解法一:orm
class Solution { public: int deleteAndEarn(vector<int>& nums) { vector<int> sums(10001, 0); int take = 0, skip = 0; for (int num : nums) sums[num] += num; for (int i = 0; i < 10001; ++i) { int takei = skip + sums[i]; int skipi = max(skip, take); take = takei; skip = skipi; } return max(skip, take); } };
下面這種解法直接使用sums數組來更新,而沒有使用額外的變量。上面解法中沒有講解這個sums數組,這裏的sums實際上至關於創建了數字和其總積分的映射,這裏的總積分的計算方法是由數字乘以其出現次數得來的。因爲題目中說了每一個數字不會超過10000,因此sums的長度能夠初始化爲10001,而後遍歷原數組,將遇到的數字都累加到該數字在數組中的位置上。而後從sums數組的第三個數字開始遍歷,更新方法跟上面解法的思路很相似,當前的sums[i]值就等於前一個值sums[i-1]和前兩個值sums[i-2]加上當前的sums[i]值中的較大值,其實思想就是在不拿當前數的積分,跟不拿前一個數的積分加上當前的積分之和,取兩者中的較大值更新當前值sums[i],參見代碼以下:htm
解法二:
class Solution { public: int deleteAndEarn(vector<int>& nums) { vector<int> sums(10001, 0); for (int num : nums) sums[num] += num; for (int i = 2; i < 10001; ++i) { sums[i] = max(sums[i - 1], sums[i - 2] + sums[i]); } return sums[10000]; } };
相似題目:
參考資料:
https://discuss.leetcode.com/topic/112807/java-c-clean-code-with-explanation