一、Problem
給你一個字符串 num 和一個整數 k 。其中,num 表示一個很大的整數,字符串中的每個字符依次對應整數上的各個 數位 。
你可以交換這個整數相鄰數位的數字 最多 k 次。
請你返回你能得到的最小整數,並以字符串形式返回。
輸入:num = "4321", k = 4
輸出:"1342"
解釋:4321 通過 4 次交換相鄰數位得到最小整數的步驟如上圖所示。
提示:
1 <= num.length <= 30000
num 只包含 數字 且不含有 前導 0 。
1 <= k <= 10^9
二、Solution
方法一:貪心地交換(超時)
思路
固定一個端點 ,從區間 中找到一個比 小的且是最小的字符,它的下標爲 mIdx(注要找到才能進行後面的交換),然後將區間 中的相鄰字符全部交換,然後得到一個數值更小的數字 num
不斷重複上面的操作,直到 k = 0
class Solution {
public:
string minInteger(string s, int k) {
int n = s.size();
for (int i = 0; i < n; i++) {
char c = s[i];
int mIdx = 0, found = 0;
for (int j = i+1; j < n && j < i+k+1; j++) {
if (s[j] < c) {
mIdx = j;
c = s[j];
found = 1;
}
}
if (!found) continue;
for (int r = mIdx; r >= i+1; r--)
swap(s[r], s[r-1]);
k -= mIdx - i;
if (k == 0)
break;
}
return s;
}
};
觀察到最後一個大的樣例,它的長度的平方 比 要小,這意味着我們最暴力的冒泡來實現暴力交換,所以加個特判
class Solution {
public:
string minInteger(string s, int k) {
int n = s.size();
if (n < k / n) {
sort(s.begin(), s.end());
return s;
}
for (int i = 0; i < n; i++) {
char c = s[i];
int mIdx = 0, found = 0;
for (int j = i+1; j < n && j < i+k+1; j++) {
if (s[j] < c) {
mIdx = j;
c = s[j];
found = 1;
}
}
if (!found) continue;
for (int r = mIdx; r >= i+1; r--)
swap(s[r], s[r-1]);
k -= mIdx - i;
if (k == 0)
break;
}
return s;
}
};
複雜度分析
- 時間複雜度:,
- 空間複雜度:,
方法二:線段樹
這題正解是線段樹,沒學過…
複雜度分析
- 時間複雜度:,
- 空間複雜度:,