[LeetCode刷題筆記] 1551 – Minimum Operations to Make Array Equal

題目描述:

You have an array arr of length n where arr[i] = (2 * i) + 1 for all valid values of i (i.e. 0 <= i < n).

In one operation, you can select two indices x and y where 0 <= x, y < n and subtract 1 from arr[x] and add 1 to arr[y] (i.e. perform arr[x] -=1and arr[y] += 1). The goal is to make all the elements of the array equal. It is guaranteed that all the elements of the array can be made equal using some operations.

Given an integer n, the length of the array. Return the minimum number of operations needed to make all the elements of arr equal.

 

Example 1:

Input: n = 3
Output: 2
Explanation: arr = [1, 3, 5]
First operation choose x = 2 and y = 0, this leads arr to be [2, 3, 4]
In the second operation choose x = 2 and y = 0 again, thus arr = [3, 3, 3].

Example 2:

Input: n = 6
Output: 9

 

Constraints:

  • 1 <= n <= 10^4

一刷題解(找出規律):

       這一題給我們一個n,這個n代表著一個有規律的數組的元素個數。其規律為:每個元素的值為其所在下標*2 + 1。也就是說,假如元素下標為0,這個元素的值則為(0*2)+1 = 1;假如元素下標為1,這個元素的值則為(1*2)+1 = 3。如此類推,我們可以得知在這個規律下,一個長度為n的數組將等同於一個列出從1開始並包括1的前n個奇數的有序數組。

        分別以n=5和n=6為例,我們可以分別列出以下數組:

  • n = 5 : {1, 3, 5, 7, 9}
  • n = 6: {1, 3, 5, 7, 9, 11}

        然後,題目讓我們找出使得這個數組所有元素值相等的最小操作次數(每次操作可使得一個元素值+1並使另一個元素值-1)。由此,我們不難想到,最好的方法必然是使數組左右兩邊(左小右大)的元素逐步調整並向中間的值靠攏。但是元素個數對這個過程也有一定的影響。

  • 比如n = 5時,數組為{1, 3, 5, 7, 9},它的運算步驟為:
    1. {1, 3 + 2, 5, 7 – 2, 9} => {1, 5, 5, 5, 9}(操作次數 = 2)
    2. {1 + 4, 5, 5, 5, 9 – 4} => {5, 5, 5, 5, 5}(操作次數 = 4)
    3. 總操作次數 = 6
  • 而當n = 6時,數組為{1, 3, 5, 7, 9, 11},它的運算步驟則為:
    1. {1, 3 + 2, 5, 7, 9 – 2, 11} => {1, 5, 5, 7, 7, 11}(操作次數 = 2,由於元素數量為偶數,因此不能以中間的值為錨點對兩側進行操作,而只能取中間兩個值作為錨點,小的一側向小的一邊進行遞增;大的一側向大的一邊進行遞減。)
    2. {1 + 4, 5, 5, 7, 7, 11 – 4} => {5, 5, 5, 7, 7, 7}(操作次數 = 4)
    3. {5 + 1, 5 + 1, 5 + 1, 7 – 1, 7 – 1, 7 – 1} => {6, 6, 6, 6, 6, 6}(操作次數 = 3)
    4. 總操作次數 = 9

        可見元素個數的奇偶,會導致結果出現一些變化,但是,其實現在已經不多不少感覺到一些規律了,比如:

  • 完成操作後的長度為n的數組中的每一個元素必然等於n
  • 單數長度的數組與雙數長度的數組,各自的內部的操作次數存在一定的成長規律。
  • 具體規律如下:
    • //變化規律
      //n = 1 => step = 0 : {1} => {1}
      //n = 2 => step = 1 : {1, 3} => {2, 2}
      //n = 3 => step = 2 : {1, 3, 5} => {3, 3, 3}
      //n = 4 => step = 4 : {1, 3, 5, 7} => {4, 4, 4, 4}
      //n = 5 => step = 6 : {1, 3, 5, 7, 9} => {5, 5, 5, 5, 5}
      //n = 6 => step = 9 : {1, 3, 5, 7, 9, 11} => {6, 6, 6, 6, 6, 6}
      //n = 7 => step = 12 :{1, 3, 5, 7, 9, 11, 13} => {7, 7, 7, 7, 7, 7, 7}
      //n = 8 => step = 16 :{1, 3, 5, 7, 9, 11, 13, 15} => {8, 8, 8, 8, 8, 8, 8, 8}

      //操作次數成長規律
      //當n為奇數:1, 3, 5, 7
      //操作次數:0, 2, 6, 12
      //成長規律:0, 2, 4, 6

      //當n為偶數:2, 4, 6, 8
      //操作次數:1, 4, 9, 16
      //成長規律:1, 3, 5, 7
  • 既然知道了n和結果操作次數的關係,就沒必要在拘泥於數組元素是怎樣操作了,直接根據n,通過總結上述規律得出的兩道公式即可找出解答。
    • n % 2 == 0(n為雙數時):
      • 運行次數增長幅度從1開始,每次增加2,n變化幅度為2
      • increaseRange = 1(default),  increaseRange += 2 per loop, n -= 2 per loop
    • n % 2 == 1(n為單數時):
      • 運行次數增長幅度從0開始,每次增加2,n變化幅度為2
      • increaseRange = 0(default), increaseRange += 2 per loop, n -= 2 per loop
public class Solution {
   public int MinOperations(int n) {
       int steps = 0;
       int increaseRate = n % 2 == 0 ? 1 : 0;

       while (n % 2 == 0 ? n >= 2 : n >= 1)
      {
           steps += increaseRate;
           increaseRate += 2;
           n -= 2;
      }
       return steps;
  }
}