# Lexicographical smallest number after at most K consecutive swaps

Given a number in form of string str and an integer K, the task is to find the smallest integer that can be formed after performing at most K consecutive swaps.

The consecutive swaps mean at one swap the character at index i can be swapped with character at index i – 1 or i + 1

Examples:

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.

Naive Approach: The simplest idea is to generate all possible permutation of the given string and check whether which lexicographically smallest string satisfies the conditions for at most K swaps. Print that string.

Time Complexity: O(N!), where N is the length of the given string.
Auxiliary Space: O(1)

Better Approach: A better approach is to use Greedy Approach. Below are the steps:

1. Remove the leading zero if exists in the given number.
2. Pick the smallest element from the string str [Consider str[k] when K is smaller, else N].
3. Place the smallest element to the 0th position after shifting all these elements by 1 position right.
4. Subtract the number of swaps in the above steps from K.
5. If still we are left with K > 0 then we apply the same procedure from the very next starting position i.e., str[2, …N], and then place it to the 1st position.
6. So we keep applying the same process until K becomes 0.

Time Complexity: O(N2), where N is the length of the given string.
Auxiliary Space: O(1)

Efficient Approach: The idea is to use the Segment tree and Hashing. Below are the steps:

1. Remove the leading zero if exists in the given number.
2. Store the original position of the digits in a Map and find which digit the best fits at every index whose shifting will be less than equal to K.
3. Use a Map to find the original position of the digit.
4. Find the number of digits that are right to the current position and that is shifted, for this, mark the position of which are shifted in a segment tree from [0 … N-1].
5. Every node of the segment tree contains the number of positions that got shifted. Now the task is to find how many positions got shifted in the range [current_index, N-1] because only that will affect the original position.
6. The new position to shift will be (original_position + number_of_right – element_shifted – i), that is the original position of the element is added to the segment tree which just got shifted.

Below is the program for the above approach:

## 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<``int``>& 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<``int``>& 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 lexicographically` `// smallest integer` `string findMinimumInteger(` `    ``string arr, ``int` `k)` `{`   `    ``// To remove leading zeros` `    ``arr = removeLeadingZeros(arr);`   `    ``int` `n = arr.size();`   `    ``// Segment tree vector` `    ``vector<``int``> seg(` `        ``(2 * (``int``)``pow``(` `                 ``2,` `                 ``(``int``)(``ceil``(log2(n))))` `         ``- 1),` `        ``0);`   `    ``// Hash to find the original` `    ``// position of the digit` `    ``unordered_map<``int``, list<``int``> > 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;` `}`

## Java

 `import` `java.util.*;`   `class` `GFG {`   `  ``// Function to mark the pos as 1 that` `  ``// are shifted in string in Segtree node` `  ``public` `static` `void` `SegAdd(``int``[] seg, ``int` `start, ``int` `end, ``int` `pos, ``int` `curr) {`   `    ``// Out of Range` `    ``if` `(pos < start || pos > end) {` `      ``return``;` `    ``}`   `    ``// Check if we reach the position` `    ``if` `(start == end) {` `      ``seg[curr] = ``1``;` `      ``return``;` `    ``}` `    ``// Initialize the mid` `    ``int` `mid = (start + end) / ``2``;` `    ``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``];` `  ``}`   `  ``// Function to find the number of` `  ``// elements which got shifted` `  ``public` `static` `int` `SegFind(``int``[] seg, ``int` `pos_start, ``int` `pos_end, ``int` `start, ``int` `end, ``int` `curr) {` `    ``if` `(pos_end < start || pos_start > end) {` `      ``return` `0``;` `    ``}`   `    ``// Return 0 is the end position is` `    ``// less than start or the start` `    ``// position is greater than end` `    ``if` `(pos_start <= start && pos_end >= end) {` `      ``return` `seg[curr];` `    ``}` `    ``int` `mid = (start + end) / ``2``;` `    ``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` `left + right;` `  ``}`   `  ``// Function to remove leading zeros` `  ``// from the given string str` `  ``public` `static` `String RemoveLeadingZeros(String s) {` `    ``int` `i = ``0``;` `    ``String ans = ``""``;` `    ``while` `(i < s.length()) {` `      ``if` `(s.charAt(i) == ``'0'``) {` `        ``i += ``1``;` `      ``} ``else` `{` `        ``break``;` `      ``}` `    ``}` `    ``ans = s.substring(i);` `    ``return` `ans;` `  ``}`   `  ``// Function to find the lexicographically` `  ``// smallest integer` `  ``public` `static` `String FindMinimumInteger(String s, ``int` `k) {` `    ``s = RemoveLeadingZeros(s);` `    ``int` `n = s.length();` `    ``int``[] seg = ``new` `int``[``2` `* (``int``) Math.pow(``2``, Math.ceil(Math.log(n) / Math.log(``2``))) - ``1``];` `    ``Map> m = ``new` `HashMap>();` `    ``for` `(``int` `i = ``0``; i < ``10``; i++) {` `      ``m.put(i, ``new` `ArrayList());` `    ``}` `    ``for` `(``int` `i = ``0``; i < n; i++) {` `      ``m.get(Integer.parseInt(String.valueOf(s.charAt(i)))).add(i);` `    ``}` `    ``String res = ``""``;` `    ``for` `(``int` `i = ``0``; i < n; i++) {` `      ``for` `(``int` `digit = ``0``; digit < ``10``; digit++) {` `        ``if` `(m.get(digit).size() != ``0``) {` `          ``int` `original_pos = m.get(digit).get(``0``);` `          ``int` `shift = SegFind(seg, original_pos, n - ``1``, ``0``, n - ``1``, ``0``);` `          ``int` `new_pos = original_pos + shift - i;` `          ``if` `(new_pos <= k) {` `            ``k -= new_pos;` `            ``SegAdd(seg, ``0``, n - ``1``, original_pos, ``0``);` `            ``res += String.valueOf(digit);` `            ``m.get(digit).remove(``0``);` `            ``break``;` `          ``}` `        ``}` `      ``}` `    ``}` `    ``return` `res;` `  ``}`   `  ``// Driver code` `  ``public` `static` `void` `main(String[] args) {` `    ``String s = ``"9438957234785635408"``;` `    ``int` `k = ``23``;` `    ``System.out.println(FindMinimumInteger(s, k));` `  ``}` `}`

## Python3

 `import` `math`   `# Function to mark the pos as 1 that` `# are shifted in string in Segtree node` `def` `segAdd(seg, start, end, pos, 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` `    ``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` `def` `segFind(seg, pos_start, pos_end, start, end, 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` `    ``mid ``=` `(start ``+` `end) ``/``/` `2` `    ``# Recursion call` `    ``left ``=` `segFind(seg, pos_start, pos_end, start, mid, ``2` `*` `curr ``+` `1``)` `    ``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` `def` `removeLeadingZeros(s):` `    ``i ``=` `0` `    ``# To store the resultant string` `    ``ans ``=` `""` `    ``while` `i < ``len``(s):` `        ``# If Initial character is 0,` `        ``# then remove it` `        ``if` `s[i] ``=``=` `'0'``:` `            ``i ``+``=` `1` `        ``# Else break` `        ``else``:` `            ``break` `    ``ans ``=` `s[i:]` `    ``# Return the updated string` `    ``return` `ans`   `# Function to find the lexicographically` `# smallest integer` `def` `findMinimumInteger(s, k):` `    ``# To remove leading zeros` `    ``s ``=` `removeLeadingZeros(s)` `    ``n ``=` `len``(s)` `    ``# Segment tree vector` `    ``seg ``=` `[``0``] ``*` `(``2` `*` `(``2` `*``*` `math.ceil(math.log2(n))) ``-` `1``)` `    ``# Hash to find the original` `    ``# position of the digit` `    ``m ``=` `{digit:[] ``for` `digit ``in` `range``(``10``)}` `    ``for` `i ``in` `range``(n):` `        ``m[``int``(s[i])].append(i)` `    ``# Resultant string variable` `    ``res ``=` `""` `    ``for` `i ``in` `range``(n):` `        ``# Place a digit from` `        ``# 0-9 which fit best` `        ``for` `digit ``in` `range``(``10``):` `            ``if` `len``(m[digit]) !``=` `0``:` `                ``original_pos ``=` `m[digit][``0``]` `                ``# Find the number of` `                ``# right elements that` `                ``# are shifted from` `                ``# current element` `                ``shift ``=` `segFind(seg, original_pos, n ``-` `1``, ``0``, n ``-` `1``, ``0``)` `                ``# Mark the new position` `                ``new_pos ``=` `original_pos ``+` `shift ``-` `i` `                ``if` `new_pos <``=` `k:` `                    ``k ``-``=` `new_pos` `                    ``# Add the original position` `                    ``# Add the original position of` `                    ``# the element which got shifted` `                    ``segAdd(seg, ``0``, n ``-` `1``,original_pos, ``0``);`   `                    ``res ``+``=` `str``(digit);` `                    ``m[digit].pop(``0``);` `                    ``break``;` `                `    `    ``# Return the result` `    ``return` `res;`   `# Driver Code`   `# Given string` `s ``=` `"9438957234785635408"``;`   `# Given K swaps` `k ``=` `23``;`   `# Function Call` `print``(findMinimumInteger(s, k))`

## C#

 `using` `System;` `using` `System.Collections.Generic;`   `class` `GFG {` `  `  `  ``// Function to mark the pos as 1 that` `  ``// are shifted in string in Segtree node` `  ``public` `static` `void` `SegAdd(``int``[] seg, ``int` `start, ``int` `end,` `                            ``int` `pos, ``int` `curr)` `  ``{`   `    ``// Out of Range` `    ``if` `(pos < start || pos > end) {` `      ``return``;` `    ``}`   `    ``// Check if we reach the position` `    ``if` `(start == end) {` `      ``seg[curr] = 1;` `      ``return``;` `    ``}`   `    ``// Initialize the mid` `    ``int` `mid = (start + end) / 2;` `    ``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];` `  ``}`   `  ``// Function to find the number of` `  ``// elements which got shifted` `  ``public` `static` `int` `SegFind(``int``[] seg, ``int` `pos_start,` `                            ``int` `pos_end, ``int` `start,` `                            ``int` `end, ``int` `curr)` `  ``{` `    ``if` `(pos_end < start || pos_start > end) {` `      ``return` `0;` `    ``}`   `    ``// Return 0 is the end position is` `    ``// less than start or the start` `    ``// position is greater than end` `    ``if` `(pos_start <= start && pos_end >= end) {` `      ``return` `seg[curr];` `    ``}` `    ``int` `mid = (start + end) / 2;` `    ``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` `left + right;` `  ``}`   `  ``// Function to remove leading zeros` `  ``// from the given string str` `  ``public` `static` `string` `RemoveLeadingZeros(``string` `s)` `  ``{` `    ``int` `i = 0;` `    ``string` `ans = ``""``;` `    ``while` `(i < s.Length) {` `      ``if` `(s[i] == ``'0'``) {` `        ``i += 1;` `      ``}` `      ``else` `{` `        ``break``;` `      ``}` `    ``}` `    ``ans = s.Substring(i);` `    ``return` `ans;` `  ``}`   `  ``// Function to find the lexicographically` `  ``// smallest integer` `  ``public` `static` `string` `FindMinimumInteger(``string` `s, ``int` `k)` `  ``{` `    ``s = RemoveLeadingZeros(s);` `    ``int` `n = s.Length;` `    ``int``[] seg` `      ``= ``new` `int``[2` `                ``* (``int``)Math.Pow(` `                  ``2,` `                  ``Math.Ceiling(Math.Log(n, 2)))` `                ``- 1];` `    ``Dictionary<``int``, List<``int``> > m` `      ``= ``new` `Dictionary<``int``, List<``int``> >();` `    ``for` `(``int` `i = 0; i < 10; i++) {` `      ``m[i] = ``new` `List<``int``>();` `    ``}` `    ``for` `(``int` `i = 0; i < n; i++) {` `      ``m[``int``.Parse(s[i].ToString())].Add(i);` `    ``}` `    ``string` `res = ``""``;` `    ``for` `(``int` `i = 0; i < n; i++) {` `      ``for` `(``int` `digit = 0; digit < 10; digit++) {` `        ``if` `(m[digit].Count != 0) {` `          ``int` `original_pos = m[digit][0];` `          ``int` `shift = SegFind(seg, original_pos,` `                              ``n - 1, 0, n - 1, 0);` `          ``int` `new_pos = original_pos + shift - i;` `          ``if` `(new_pos <= k) {` `            ``k -= new_pos;` `            ``SegAdd(seg, 0, n - 1, original_pos,` `                   ``0);` `            ``res += Convert.ToString(digit);` `            ``m[digit].RemoveAt(0);` `            ``break``;` `          ``}` `        ``}` `      ``}` `    ``}` `    ``return` `res;` `  ``}`   `  ``// Driver code` `  ``public` `static` `void` `Main(``string``[] args)` `  ``{` `    ``string` `s = ``"9438957234785635408"``;` `    ``int` `k = 23;`   `    ``// Function call` `    ``Console.WriteLine(FindMinimumInteger(s, k));` `  ``}` `}`

## Javascript

 `// Function to mark the pos as 1 that` `// are shifted in string in Segtree node` `function` `segAdd(seg, start, end, pos, curr) {`   `  ``// Out of Range` `  ``if` `(pos < start || pos > end) {` `    ``return``;` `  ``}` `  `  `  ``// Check if we reach the position` `  ``if` `(start == end) {` `    ``seg[curr] = 1;` `    ``return``;` `  ``}` `  `  `  ``// Initialize the mid` `  ``const mid = Math.floor((start + end) / 2);` `  ``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];` `}`   `// Function to find the number of` `// elements which got shifted` `function` `segFind(seg, pos_start, pos_end, start, end, curr) {` `  ``if` `(pos_end < start || pos_start > end) {` `    ``return` `0;` `  ``}` `  `  `  ``// Return 0 is the end position is` `  ``// less than start or the start` `  ``// position is greater than end` `  ``if` `(pos_start <= start && pos_end >= end) {` `    ``return` `seg[curr];` `  ``}` `  ``const mid = Math.floor((start + end) / 2);` `  ``const left = segFind(seg, pos_start, pos_end, start, mid, 2 * curr + 1);` `  ``const right = segFind(seg, pos_start, pos_end, mid + 1, end, 2 * curr + 2);` `  ``return` `left + right;` `}`   `// Function to remove leading zeros` `// from the given string str` `function` `removeLeadingZeros(s) {` `  ``let i = 0;` `  ``let ans = ``""``;` `  ``while` `(i < s.length) {` `    ``if` `(s[i] == ``"0"``) {` `      ``i += 1;` `    ``} ``else` `{` `      ``break``;` `    ``}` `  ``}` `  ``ans = s.substring(i);` `  ``return` `ans;` `}`   `// Function to find the lexicographically` `// smallest integer` `function` `findMinimumInteger(s, k) {` `  ``s = removeLeadingZeros(s);` `  ``const n = s.length;` `  ``const seg = ``new` `Array(2 * 2 ** Math.ceil(Math.log2(n)) - 1).fill(0);` `  ``const m = {};` `  ``for` `(let i = 0; i < 10; i++) {` `    ``m[i] = [];` `  ``}` `  ``for` `(let i = 0; i < n; i++) {` `    ``m[parseInt(s[i])].push(i);` `  ``}` `  ``let res = ``""``;` `  ``for` `(let i = 0; i < n; i++) {` `    ``for` `(let digit = 0; digit < 10; digit++) {` `      ``if` `(m[digit].length != 0) {` `        ``const original_pos = m[digit][0];` `        ``const shift = segFind(seg, original_pos, n - 1, 0, n - 1, 0);` `        ``const new_pos = original_pos + shift - i;` `        ``if` `(new_pos <= k) {` `          ``k -= new_pos;` `          ``segAdd(seg, 0, n - 1, original_pos, 0);` `          ``res += digit.toString();` `          ``m[digit].shift();` `          ``break``;` `        ``}` `      ``}` `    ``}` `  ``}` `  ``return` `res;` `}`   `// Driver code`   `const s = ``"9438957234785635408"``;` `const k = 23;`   `console.log(findMinimumInteger(s, k));`

Output:

`0345989723478563548`

Time Complexity: O(N * log N), where N is the length of the string.
Auxiliary Space: O(N)

Feeling lost in the world of random DSA topics, wasting time without progress? It's time for a change! Join our DSA course, where we'll guide you on an exciting journey to master DSA efficiently and on schedule.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 geeks!

Previous
Next