【貪心】A044_LC_最多 K 次交換相鄰數位後得到的最小整數(暴力掃描最小的字符 / 線段樹)

一、Problem

給你一個字符串 num 和一個整數 k 。其中,num 表示一個很大的整數,字符串中的每個字符依次對應整數上的各個 數位 。

你可以交換這個整數相鄰數位的數字 最多 k 次。

請你返回你能得到的最小整數,並以字符串形式返回。
在這裏插入圖片描述

輸入:num = "4321", k = 4
輸出:"1342"
解釋:4321 通過 4 次交換相鄰數位得到最小整數的步驟如上圖所示。

提示:

1 <= num.length <= 30000
num 只包含 數字 且不含有 前導 0 。
1 <= k <= 10^9

二、Solution

方法一:貪心地交換(超時)

思路

固定一個端點 ii,從區間 [i, i+k][i, \ i+k] 中找到一個比 s[i]s[i] 小的且是最小的字符,它的下標爲 mIdx(注要找到才能進行後面的交換),然後將區間 [i,mIdx][i, 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;
    }
};

觀察到最後一個大的樣例,它的長度的平方 n2n^2kk 要小,這意味着我們最暴力的冒泡來實現暴力交換,所以加個特判

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;
    }
};

複雜度分析

  • 時間複雜度:O(n2)O(n^2)
  • 空間複雜度:O(1)O(1)

方法二:線段樹

這題正解是線段樹,沒學過…


複雜度分析

  • 時間複雜度:O()O()
  • 空間複雜度:O()O()
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章