一、題目
給你兩個長度可能不等的整數數組 nums1
和 nums2
。兩個數組中的所有值都在 1
到 6
之間(包含 1 和 6)。
每次操作中,你可以選擇 任意 數組中的任意一個整數,將它變成 1
到 6
之間 任意 的值(包含 1
和 6
)。
請你返回使 nums1
中所有數的和與 nums2
中所有數的和相等的最少操作次數。如果無法使兩個數組的和相等,請返回 -1
。
二、示例
2.1> 示例 1:
【輸入】nums1 = [1,2,3,4,5,6], nums2 = [1,1,2,2,2,2]
【輸出】3
【解釋】你可以通過 3 次操作使 nums1 中所有數的和與 nums2 中所有數的和相等。以下數組下標都從 0 開始。
- 將 nums2[0] 變為 6 。 nums1 = [1,2,3,4,5,6], nums2 = [6,1,2,2,2,2] 。
- 將 nums1[5] 變為 1 。 nums1 = [1,2,3,4,5,1], nums2 = [6,1,2,2,2,2] 。
- 將 nums1[2] 變為 2 。 nums1 = [1,2,2,4,5,1], nums2 = [6,1,2,2,2,2] 。
2.2> 示例 2:
【輸入】nums1 = [1,1,1,1,1,1,1], nums2 = [6]
【輸出】-1
【解釋】沒有辦法減少 nums1 的和或者增加 nums2 的和使二者相等。
2.3> 示例 3:
【輸入】nums1 = [6,6], nums2 = [1]
【輸出】3
【解釋】你可以通過 3 次操作使 nums1 中所有數的和與 nums2 中所有數的和相等。以下數組下標都從 0 開始。
- 將 nums1[0] 變為 2 。 nums1 = [2,6], nums2 = [1] 。
- 將 nums1[1] 變為 2 。 nums1 = [2,2], nums2 = [1] 。
- 將 nums2[0] 變為 4 。 nums1 = [2,2], nums2 = [4] 。
提示:
-
1
<= nums1.length, nums2.length <=10^5
-
1
<= nums1[i], nums2[i] <=6
三、解題思路
首先,根據題意,我們需要計算出數組nums1
和nums2
之間,最小的操作次數,使得nums1的總和:sum(nums1)
與nums2的總和:sum(nums2)
兩個值相等。那么我們可以根據如下4個步驟來解決這個問題:
【步驟1】分別計算sum(nums1)
和sum(nums2)
的值,確定兩個數組加和的差值diff
,以及sum(nums1)
和sum(nums2)
之間的大小關系。
【步驟2】將總和較小的數組賦值為int[] smaller
,將總和較大的數組賦值為int[] bigger
。
對于
smaller
數組中的每個值,我們要執行變大操作,其中:由于最大值是6,所以每個元素s變大的最大跨度是:6 - s
;
對于bigger
數組中的每個值,我們要執行變小操作,其中:由于最小值是1,所以每個元素b變大的最大跨度是:b - 1
;
【步驟3】創建一個用于存儲跨度&出現次數的數組int[] range
(也可以采用Map結構),其中:下標index
表示跨度值,range[index]
表示該跨度值出現的次數。由于題目中指出,nums1和nums2中元素的值的范圍是[1, 6]
,所以,對應的跨度值就是[0, 5]
。為了便于畫圖,圖中采用Map結構表示:
【步驟4】由于要求計算出最小操作次數,所以我們需要從range
數組末尾開始遍歷執行對比操作,以上面圖中的例子做演示,diff=11
,range=[1,1,1,1,5,3]
:
【第1次操作】因為差值diff > 跨度5,所以差值diff變為
6
(11減5),range[5]的出現次數變為2
(3減1);
【第2次操作】因為差值diff > 跨度5,所以差值diff變為1
(6減5),range[5]的出現次數變為1
(2減1);
【第3次操作】因為差值diff <= 跨度5,滿足題解,返回最少操作次數為:3。
四、代碼實現
class Solution {
public int minOperations(int[] nums1, int[] nums2) {
int result = 0, l1 = nums1.length, l2 = nums2.length, sum1 = 0, sum2 = 0, diff;
if (6 * l1 < l2 || 6 * l2 < l1) return -1; // 無法使兩個數組的和相等,返回-1
for (int n1 : nums1) sum1 += n1;
for (int n2 : nums2) sum2 += n2;
if ((diff = Math.abs(sum1 - sum2)) == 0) return 0; // 如果兩個數組和相等,則不需要操作,返回0
int[] range = calculate(nums1, nums2, sum1, sum2);
for (int i = 5; i >= 0; i--) { // 從最大的差值開始對比
while (range[i] > 0) { // 如果差值range[i]出現的次數不為0
result++; // 操作次數加1
if (i >= diff) return result; // 如果差值大于等于diff,則操作結束,返回操作數result
range[i]--; // 差值range[i]的出現次數減1
diff -= i; // 更新diff值
}
}
return -1;
}
// 計算每個差值(1~5)出現的次數
private int[] calculate(int[] nums1, int[] nums2, int sum1, int sum2) {
int[] bigger = (sum1 < sum2) ? nums2 : nums1;
int[] smaller = (sum1 < sum2) ? nums1 : nums2;
int[] range = new int[6]; // index:差值 range[index]:該差值出現的次數
for (int s : smaller) ++range[6 - s]; // 對于總數較小的數組,要執行增加操作,由于理論上最大值是6,所以最大可以增加"6-s"個數值
for (int b : bigger) ++range[b - 1]; // 對于總數較大的數組,要執行減法操作,由于理論上最小值是1,所以最大可以減少"b-1"個數值
return range;
}
}
今天的文章內容就這些了:
寫作不易,筆者幾個小時甚至數天完成的一篇文章,只愿換來您幾秒鐘的 點贊 & 分享 。
更多技術干貨,歡迎大家關注公眾號“爪哇繆斯” ~ \(o)/ ~ 「干貨分享,每天更新」