題目連結:
題目意譯:
你被給定一個整數陣列 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 比較看何者小即為所求。
此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。