给定一个字符串str形式的数字和一个整数K ,任务是找到最多执行K个连续交换后可以形成的最小整数。
The consecutive swaps mean at one swap the character at index i can be swapped with character at index i – 1 or i + 1.
例子:
Input: str = “76921”, K = 3
Output: 27691
Explanation:
27691 is the lexicographical smallest possible number.
Input: str = “9438957234785635408”, K = 23
Output: 0345989723478563548
Explanation:
0345989723478563548 is the lexicographical smallest possible number.
朴素的方法:最简单的想法是生成给定字符串的所有可能排列,并检查哪个字典序最小的字符串是否满足最多K 次交换的条件。打印那个字符串。
时间复杂度: O(N!),其中 N 是给定字符串的长度。
辅助空间: O(1)
更好的方法:更好的方法是使用贪婪方法。以下是步骤:
- 如果给定数字中存在前导零,则删除前导零。
- 从字符串str 中选取最小的元素[当K较小时考虑str[k] ,否则为N ]。
- 将所有这些元素向右移动 1 个位置后,将最小的元素放在第 0 个位置。
- 从K 中减去上述步骤中的交换次数。
- 如果仍然剩下K > 0,那么我们从下一个起始位置即str[2, …N]应用相同的过程,然后将其放置到第一个位置。
- 所以我们继续应用相同的过程,直到K 变为 0 。
时间复杂度: O(N 2 ),其中 N 是给定字符串的长度。
辅助空间: O(1)
高效的方法:想法是使用Segment tree和Hashing 。以下是步骤:
- 如果给定数字中存在前导零,则删除前导零。
- 将数字的原始位置存储在 Map 中,并在每个位移小于等于K 的索引处找到最适合的数字。
- 使用地图查找数字的原始位置。
- 找到当前位置右侧并被移位的位数,为此,标记其在段树中从[0 … N-1]移位的位置。
- 线段树的每个节点都包含移位的位置数。现在的任务是找出在[current_index, N-1]范围内移动了多少位置,因为只有这样才会影响原始位置。
- 要移位的新位置将是(original_position + number_of_right – element_shifted – i),即元素的原始位置被添加到刚刚移位的线段树中。
以下是上述方法的程序:
C++
// C++ program for the above approach
#include
using namespace std;
// Function to mark the pos as 1 that
// are shifted in string in Segtree node
void segAdd(vector& seg, int start,
int end, int pos, int curr)
{
// Out of Range
if (pos < start or pos > end)
return;
// Check if we reach the position
if (start == end) {
seg[curr] = 1;
return;
}
// Initialize the mid
int mid = (start + end) / 2;
// Recursion call
segAdd(seg, start, mid, pos,
2 * curr + 1);
segAdd(seg, mid + 1, end, pos,
2 * curr + 2);
// Every node contains no of
// marked position that are
// shifted in a range
seg[curr] = seg[2 * curr + 1]
+ seg[2 * curr + 2];
return;
}
// Function to find the number of
// elements which got shifted
int segFind(
vector& seg, int pos_start,
int pos_end, int start, int end,
int curr)
{
// Return 0 is the end position is
// less than start or the start
// position is greater than end
if (pos_end < start
or pos_start > end)
return 0;
if (pos_start <= start
and pos_end >= end)
return seg[curr];
// Initialize the mid
int mid = (start + end) / 2;
// Recursion call
int left = segFind(
seg, pos_start, pos_end,
start, mid, 2 * curr + 1);
int right = segFind(
seg, pos_start, pos_end,
mid + 1, end, 2 * curr + 2);
// Return the result
return left + right;
}
// Function to remove leading zeros
// from the given string str
string removeLeadingZeros(string str)
{
int i = 0;
// To store the resultant string
string ans = "";
for (; i < str[i]; i++) {
// If Initial character is 0,
// then remove it
if (str[i] == '0') {
i++;
}
// Else break
else {
break;
}
}
ans = str.substr(i - 1,
str.length());
// Return the updated string
return ans;
}
// Function to find the lexiographically
// smallest integer
string findMinimumInteger(
string arr, int k)
{
// To remove leading zeros
arr = removeLeadingZeros(arr);
int n = arr.size();
// Segment tree vector
vector seg(
(2 * (int)pow(
2,
(int)(ceil(log2(n))))
- 1),
0);
// Hash to find the original
// position of the digit
unordered_map > m;
for (int i = 0; i < n; i++) {
m[arr[i] - '0'].push_back(i);
}
// Resultant string variable
string res = "";
for (int i = 0; i < n; i++) {
// Place a digit from
// 0-9 which fit best
for (int digit = 0;
digit <= 9; digit++) {
if (m[digit].size() != 0) {
int original_pos
= m[digit].front();
// Find the number of
// right elements that
// are shifted from
// current element
int shift
= segFind(
seg, original_pos,
n - 1, 0, n - 1, 0);
// Mark the new position
int new_pos = original_pos
+ shift
- i;
if (new_pos <= k) {
k -= new_pos;
// Add the original position of
// the element which got shifted
segAdd(seg, 0, n - 1,
original_pos, 0);
res.push_back('0' + digit);
m[digit].pop_front();
break;
}
}
}
}
// Return the result
return res;
}
// Driver Code
int main()
{
// Given string
string s = "9438957234785635408";
// Given K swaps
int k = 23;
// Function Call
cout << findMinimumInteger(s, k)
<< endl;
}
0345989723478563548
时间复杂度: O(N * log N),其中 N 是字符串的长度。
辅助空间: O(N)