ETH官方钱包

前往
大廳
主題

LeetCode - 910. Smallest Range II 解題心得

Not In My Back Yard | 2022-11-12 12:00:08 | 巴幣 0 | 人氣 269

題目連結:


題目意譯:
你被給定一個整數陣列 nums 以及一個整數 k。

對於每個索引值 i,其中 0 ≦ i < nums.length,請將 nums[i] 變為 nums[i] + k 或是 nums[i] - k。

nums之分數定義為 nums 中最大值與最小值之差值。

回傳將每個索引值的數字改變之後所能得到的最小 nums 分數值。

限制:
1 ≦ nums.length ≦ 10 ^ 4
0 ≦ nums[i] ≦ 10 ^ 4
0 ≦ k ≦ 10 ^ 4



範例測資:
範例 1:
輸入: nums = [1], k = 0
輸出: 0
解釋: 分數為 max(nums) - min(nums) = 1 - 1 = 0。

範例 2:
輸入: nums = [0,10], k = 2
輸出: 6
解釋: 將 nums 變為 [2, 8]。分數為 max(nums) - min(nums) = 8 - 2 = 6。

範例 3:
輸入: nums = [1,3,6], k = 3
輸出: 3
解釋: 將 nums 變為 [4, 6, 3]。分數為 max(nums) - min(nums) = 6 - 3 = 3。


解題思維:
首先我們將 nums 中的數字由小排到大。現在 nums 中第一個元素 nums[0] 為最小值(下稱為 L)、最後一個元素 nums[nums.length - 1] 則為最大值(下稱為 R)。

可以看到我們得到最小的分數值的方式可以簡化為以下三種策略(實為兩種):
策略一:將所有元素統一減 k;

策略二:將所有元素統一加 k;

策略三:以某個索引值 i 為中心,L ~ nums[i] 的數字統一加 k 、 nums[i + 1] ~ R 的數字統一減 k。

而藉由比較策略一、二和三得出的結果便可知最小分數值。



可以看到策略一、二基本上是長一樣的,分數值都是 R - L。

那為什麼策略三比其他的策略(除了策略一、二以外)有優勢呢?

假設我們經由策略三找到一個索引值 x 是最佳解,則此時可以看到如果我們把 L ~ nums[x] 中某些數字(可能包含 L 和 nums[x] 本身)改成變成減 k,會有以下三種情形:
一:所有數字都變成減 k,則此時變成等價於策略一,可以忽略(因為本來就要跟策略一比較);

二:新變化的數字範圍依舊落在 L + k ~ nums[x] + k,則代表這個改變毫無意義,分數值不會變得更小;

三:新變化的數字範圍超出了 L + k ~ nums[x] + k,而我們可以看到此時其必小於 L + k(因為我們改選擇「減 k」),因此只會多出比原本的解還糟的可能性(有可能不會更糟,因為還要跟右半部的數字最小值去比對)。

因此 L ~ nums[x] 應統一加上 k。而與上同理,nums[x + 1] ~ R 應統一減去 k。



有了以上結論之後,我們就可以窮舉所有索引值 i 來實現策略三。

而我們可以看到當 L ~ nums[i] 的數字統一加 k 、 nums[i + 1] ~ R 的數字統一減 k 的時候,最小值只可能是 L + k 或是 nums[i + 1] - k。因為排在 L 之後的數字必定不小於 L(因為已排序了);同樣地,排在 nums[i + 1] 之後的必定不小於 nums[i + 1]。

同理,最大值只可能會是 nums[i] + k 或是 R - k。

因此對於每個索引值 i,分數值即為
max(R - k, nums[i] + k) - min(L + k, nums[i + 1] - k)

以此找到策略三的最小分數值後,與策略一和二的 R - L 比較看何者小即為所求。




此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。

創作回應

更多創作