leetcode_1: 最少移動次數問題

453:最小移動次數使數組元素相等

題目描述:
給定一個長度爲 n 的非空整數數組,找到讓數組所有元素相等的最小移動次數。每次移動可以使 n - 1 個元素增加 1。

示例:
輸入:
[1,2,3]
輸出:
3
解釋:
只需要3次移動(注意每次移動只會增加兩個元素的值):
[1,2,3] => [2,3,3] => [3,4,3] => [4,4,4]

思路:
n-1個元素同時加1等價於某個元素減1

代碼:

class Solution {
public:
    int minMoves(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int length = nums.size();
        int sum = 0;
        for(int i=1;i<length;i++)
        {
            sum += nums[i] - nums[0];
        }
        return sum;
    }
};

462. 最少移動次數使數組元素相等 II

題目描述:
給定一個非空整數數組,找到使所有數組元素相等所需的最小移動數,其中每次移動可將選定的一個元素加1或減1。 您可以假設數組的長度最多爲10000。

示例:
輸入:
[1,2,3]
輸出:
2
解釋:
只有兩個動作是必要的(記得每一步僅可使其中一個元素加1或減1):
[1,2,3] => [2,2,3] => [2,2,2]

思路:
中位數是最優解。
證明:假設有2n+1個數,升序排序爲…a, m, b…,其中m是中位數,那麼m左邊有n個數,右邊也有n個數。我們假設將左邊的數變成m的代價爲x,右邊的數變成m的代價爲y,此時的總代價是t=x+y。下面我們嘗試把所有的數都轉變成a,則a右面的數轉變成a的代價爲y+(m-a)*(n+1), a左邊的數轉變成a的代碼爲x-(m-a)*n,則總代價爲t=x+y+m-a,同理,如果把所有的數都轉變成b,則總代價爲t=x+y+b-m。由此可見,當總數爲2n+1時,選擇中位數是最優解。
假設有2n個數,升序排序爲…a, b…,這樣a左邊有n-1個數,b右邊有n+1個數。假設a左邊數轉換成a的代價爲x,b右邊的數轉換爲a的代價爲y,總代價爲t=x+y+b-a。嘗試將所有數都轉換爲b,則總代價爲t=x + (b-a)n + y - (b-a)(n-1) = x + y + b- a。對於總數爲偶數的情況,選擇兩個中位數的移動步數都是一樣的。

代碼:

class Solution {
public:
    int minMoves2(vector<int>& nums) {
        sort(nums.begin(),nums.end());
        int length = nums.size();
        int mid = nums[length/2];
        int sum = 0;
        for(int i=0;i<length;i++)
        {
            sum += (nums[i] > mid) ? (nums[i] - mid) : (mid - nums[i]);
        }
        return sum;
    }
};

注:可用二分法查找中位數,複雜度更低

921. 使括號有效的最少添加

題目描述:
給定一個由 ‘(’ 和 ‘)’ 括號組成的字符串 S,我們需要添加最少的括號( ‘(’ 或是 ‘)’,可以在任何位置),以使得到的括號字符串有效。

從形式上講,只有滿足下面幾點之一,括號字符串纔是有效的:

  • 它是一個空字符串,或者

  • 它可以被寫成 AB (A 與 B 連接), 其中 A 和 B 都是有效字符串,或者

  • 它可以被寫作 (A),其中 A 是有效字符串。

給定一個括號字符串,返回爲使結果字符串有效而必須添加的最少括號數。

示例1:
輸入:"())"
輸出:1
示例 2:
輸入:"((("
輸出:3
示例 3:
輸入:"()"
輸出:0
示例 4:
輸入:"()))(("
輸出:4

提示:

  1. S.length <= 1000

  2. S 只包含 ‘(’ 和 ‘)’ 字符。

思路:
遍歷字符串,設置兩個變量,left表示’(‘的數目,right表示’)‘的數目。當遇見’(‘的時,left++;當遇見’)‘時,如果left>0,就說明前面有與’)‘匹配的’(’,則需要將left–;如果left<0,說明’)‘不可匹配,right++。最後返回left+right,即是不能匹配的’(‘和’)'的總數目。

代碼:

class Solution {
public:
    int minAddToMakeValid(string S) {
        int length = S.length();
        int left = 0;
        int right = 0;
        for(int i=0;i<length;i++){
            if(S[i] == '('){
                left++;
            }else if(S[i] == ')'){
                if(left){
                    left--;
                }else{
                    right++;
                }
            }
        }
        return left + right;
    }
};

801. 使序列遞增的最小交換次數

題目描述:
我們有兩個長度相等且不爲空的整型數組 A 和 B 。我們可以交換 A[i] 和 B[i] 的元素。注意這兩個元素在各自的序列中應該處於相同的位置。在交換過一些元素之後,數組 A 和 B 都應該是嚴格遞增的(數組嚴格遞增的條件僅爲A[0] < A[1] < A[2] < … < A[A.length - 1])。

給定數組 A 和 B ,請返回使得兩個數組均保持嚴格遞增狀態的最小交換次數。假設給定的輸入總是有效的。

示例:
輸入: A = [1,3,5,4], B = [1,2,3,7]
輸出: 1
解釋:
交換 A[3] 和 B[3] 後,兩個數組如下:
A = [1, 3, 5, 7] , B = [1, 2, 3, 4]
兩個數組均爲嚴格遞增的。

注意:

  • A, B 兩個數組的長度總是相等的,且長度的範圍爲 [1, 1000]。

  • A[i], B[i] 均爲 [0, 2000]區間內的整數。

思路:
根據官方題解纔看明白具體是怎麼回事。
本題使用動態規劃思想,判定A[i]和B[i]是否交換時,需要考慮它們之前的元素A[i-1]和B[i-1]進行被交換。那麼我們先定義:n1 表示數組A和B滿足前i - 1個元素分別嚴格遞增,並且 A[i - 1] 和 B[i - 1] 未被交換的最小交換次數,s1 表示 A[i - 1] 和 B[i - 1] 被交換的最小交換次數。用n2和s2分別表示前i個元素嚴格遞增時,A[i]和B[i]未被交換和被交換的最小次數。

下面考慮兩種情況:

  • 如果A[i-1]< A[i],並且B[i-1]< B[i],如果A[i-1]和B[i-1]未交換,那麼A[i]和B[i]就不需要交換,故n2=min(n2,n1);如果A[i-1]和B[i-1]被交換,那麼A[i]和B[i]也要被交換,故s2=min(s2, s1+1)。

  • 如果A[i-1] < B[i],並且B[i-1] < A[i],那麼A[i-1]和B[i-1],A[i]和B[i]必須被交換一對才能滿足嚴格遞增,故n2 = min(n2, s2)和s2 = min(s2, n1 + 1)

上面兩種情況可能會同時發生,不過我自己考慮,會把第一種情況忽略掉,第二種相對比較直觀好理解些。

代碼:

class Solution {
public:
    int minSwap(vector<int>& A, vector<int>& B) {
        int length = A.size();
        int n1 = 0;
        int s1 = 1;
        for(int i=1;i<length;i++){
            int n2=2001;
            int s2=2001;
            if(A[i-1]<A[i] && B[i-1]<B[i]){
                n2 = Min_num(n2, n1);
                s2 = Min_num(s2, s1 + 1);
            }
            if(A[i-1] < B[i] && B[i-1] < A[i])
            {
                n2 = Min_num(n2, s1);
                s2 = Min_num(s2, n1 + 1);
            }
            n1 = n2;
            s1 = s2;
        }
        return Min_num(n1,s1);
    }
    int Min_num(int a, int b){
        return a<b?a:b;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章