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
提示:
-
S.length <= 1000
-
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;
}
};