1. 程式人生 > >其它 >LeetCode 每日一題 740. 刪除並獲得點數

LeetCode 每日一題 740. 刪除並獲得點數


740. 刪除並獲得點數

給你一個整數陣列 nums ,你可以對它進行一些操作。

每次操作中,選擇任意一個 nums[i] ,刪除它並獲得 nums[i] 的點數。之後,你必須刪除每個等於 nums[i] - 1 或 nums[i] + 1 的元素。

開始你擁有 0 個點數。返回你能通過這些操作獲得的最大點數。

示例 1:

輸入:nums = [3,4,2]
輸出:6
解釋:
刪除 4 獲得 4 個點數,因此 3 也被刪除。
之後,刪除 2 獲得 2 個點數。總共獲得 6 個點數。

示例 2:

輸入:nums = [2,2,3,3,3,4]
輸出:9
解釋:
刪除 3 獲得 3 個點數,接著要刪除兩個 2 和 4 。
之後,再次刪除 3 獲得 3 個點數,再次刪除 3 獲得 3 個點數。
總共獲得 9 個點數。

提示:

  • 1 <= nums.length <= 2 * 104
  • 1 <= nums[i] <= 104

方法一:動態規劃

思路

打家劫舍 換了一個馬甲~

先假設資料量足夠,即 [1,10000] 每個數字都有。根據題意 一旦選擇了某個數字 x,x - 1 和 x + 1 都無法選擇了,若存在多個 x,是可以進行累加的。所以每個數字對應的點數是 數字 * 個數。

對於 [1,10000] 中的每個數字,我們有 選擇 或 不選擇 兩種方案,且不能選擇相鄰的數字。這就和 打家劫舍 問題一毛一樣了~。

定義狀態 dp[i] 表示遍歷到數字 i 時能獲得的最多點數。狀態轉移方程如下,其中 sum[i] 為 數字 i * i 的個數:

  • 選擇數字 i 的累計點數 = dp[i - 2] + sum[i]
  • 不選擇數字 i 的累計點數 = dp[i - 1]
  • 即 dp[i] = max( dp[i - 2] + sum[i], dp[i - 1])

細節

  • 沒有必要構建 [0, 1000] 這麼大的陣列,根據陣列最大值 max 去構建 [0, max] 的陣列即可。

參考程式碼

 public int deleteAndEarn(int[] nums) {
 	// 構建 sum 陣列,即 數字 * 個數,作為 [打家劫舍] 問題的入參
    int max = Arrays.stream(nums).max().getAsInt();
    int[] sum = new int[max + 1];
    for (int x : nums) {
        sum[x] += x;
    }
    return rob(sum);
}

// 打家劫舍程式碼
public int rob(int[] sum) {
    int n = sum.length;
    int[] dp = new int[n];
    dp[0] = sum[0];
    dp[1] = Math.max(sum[0], sum[1]);
    for (int i = 2; i < n; i++) {
        dp[i] = Math.max(dp[i - 2] + sum[i], dp[i - 1]);
    }
    return dp[n - 1];
}

執行結果

LeetCode 每日一題 740. 刪除並獲得點數