【贪心】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

方法一:贪心地交换(超时)

思路

固定一个端点 i i i,从区间 [ i ,   i + k ] [i, \ i+k] [i, i+k] 中找到一个比 s [ i ] s[i] s[i] 小的且是最小的字符,它的下标为 mIdx(注要找到才能进行后面的交换),然后将区间 [ i , m I d x ] [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;
    }
};

观察到最后一个大的样例,它的长度的平方 n 2 n^2 n2 k k k 要小,这意味着我们最暴力的冒泡来实现暴力交换,所以加个特判

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 ( n 2 ) O(n^2) O(n2)
  • 空间复杂度: O ( 1 ) O(1) O(1)

方法二:线段树

这题正解是线段树,没学过…


复杂度分析

  • 时间复杂度: O ( ) O() O()
  • 空间复杂度: O ( ) O() O()

你可能感兴趣的:(#,【贪心】,贪心交换,线段树)