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:
- Remove the leading zero if exists in the given number.
- Pick the smallest element from the string str [Consider str[k] when K is smaller, else N].
- Place the smallest element to the 0th position after shifting all these elements by 1 position right.
- Subtract the number of swaps in the above steps from K.
- 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.
- 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:
- Remove the leading zero if exists in the given number.
- 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.
- Use a Map to find the original position of the digit.
- 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].
- 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.
- 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++ program for the above approach #include <bits/stdc++.h> 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;
} |
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<Integer, List<Integer>> m = new HashMap<Integer, List<Integer>>();
for ( int i = 0 ; i < 10 ; i++) {
m.put(i, new ArrayList<Integer>());
}
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));
}
} |
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))
|
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));
}
} |
// 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)); |
0345989723478563548
Time Complexity: O(N * log N), where N is the length of the string.
Auxiliary Space: O(N)