Find the lexicographically smallest string by prepending characters
Last Updated :
08 Mar, 2024
Two Players A and B are playing a game using a non-empty string S of length N having lowercase English Alphabets. The length of string S is even. Each player also has a string of their own, initially empty. In one move, a player takes either the first or the last character of the string S, removes it from S and prepends it (adds to the beginning) to their own string. The game ends when the string S becomes empty. The winner is the player with the lexicographically smaller string. If the players' string are equal, then it's a draw. The task is to determine the winner of the game or if the game ends in a draw.
Note: Player A starts the game.
Examples:
Input: S = "geek"
Output: A
Explanation: Player A can always manage to win:
- Player A chooses 'g', then Player B chooses 'e', then Player A chooses 'e' and Player B chooses 'k'. Final String of Player A = "eg" and final string of Player B = "ke".
- Player A chooses 'g' then Player B chooses 'k', then Player A chooses 'e' and Player B chooses 'e'. Final String of Player A = "eg" and final string of Player B = "ek".
In both the cases, Player A can always have a lexicographically smaller string, therefore Player A is the winner.
Input: S = "gffg"
Output: Draw
Explanation: It can be seen that the game will always end in a draw if both the player play optimally.
Approach: To solve the problem, follow the below idea:
The problem can be solved using Dynamic Programming. Maintain a 2D array dp[][], such that dp[l][r] stores the winner for substring S[l:r]. Declare a recursive function, say solve(l, r) which returns integers corresponding to the outcomes:
- If the outcome is a draw, then return 0.
- If the player A wins, then return 1.
- If the player B wins, then return 2.
At any state(l, r), Player A will choose one character, say c and then Player B will choose another character, say d. Then, they both prepended the characters to their string and continued the game with the smaller string S. Now, if we want to calculate the outcome of state (l, r) from (l', r'), then we can say that we append the letters c and d.
Let's say the new state becomes (l', r'). So, if the outcome of (l', r') is not a Draw, then the outcome will remain unchanged for state(l, r). Otherwise, if the outcome of state (l', r') is a draw, then the outcome depends on the characters c and d.
Explore all the cases, where the player A can start from the beginning as well as from the end. If at any end, Player A can guarantee the win then Player A can win, otherwise the game might end in a Draw or Player B winning the game.
The final answer will be at dp[0][N-1].
Step-by-step algorithm:
- Maintain a 2D array dp[][], such that dp[l][r] stores the winner for substring S[l...r].
- For a substring S[l...r], explore all the four cases by choosing different letters from different sides:
- Player A chooses from the front and Player B chooses from the front, dp[l + 2, r].
- Player A chooses from the front and Player B chooses from the back, dp[l + 1, r - 1].
- Player A chooses from the back and Player B chooses from the front, dp[l + 1, r - 1].
- Player A chooses from the back and Player B chooses from the back, dp[l, r - 2].
- Check for the current characters chosen along with the solutions of the subproblems to find the winner of the game.
- The answer will be stored at dp[0][N-1].
Below is the implementation of the algorithm:
C++
#include <bits/stdc++.h>
using namespace std;
// method to find the winner of the game
// return 0 if there is a draw, 1 if A wins and 2 if B wins
int solve(string s, int l, int r, vector<vector<int> >& dp)
{
if (r - l == 1) {
if (s[l] == s[r])
return 0;
return 1;
}
if (dp[l][r] != -1) {
return dp[l][r];
}
// A chooses the character at index l and B chooses the
// character at index r
int res1 = solve(s, l + 1, r - 1, dp);
// If the result is a draw then the answer will be
// decided by the characters at index l and r
if (res1 == 0) {
if (s[l] < s[r])
res1 = 1;
else if (s[l] > s[r])
res1 = 2;
}
// A chooses the character at index l and B chooses the
// character at index l + 1
int res2 = solve(s, l + 2, r, dp);
// If the result is a draw then the answer will be
// decided by the characters at index l and l + 1
if (res2 == 0) {
if (s[l] < s[l + 1])
res2 = 1;
else if (s[l] > s[l + 1])
res2 = 2;
}
// A chooses the character at index r and B chooses the
// character at index l
int res3 = solve(s, l + 1, r - 1, dp);
// If the result is a draw then the answer will be
// decided by the characters at index l and r
if (res3 == 0) {
if (s[l] > s[r])
res3 = 1;
else if (s[l] < s[r])
res3 = 2;
}
// A chooses the character at index r and B chooses the
// character at index r - 1
int res4 = solve(s, l, r - 2, dp);
// If the result is a draw then the answer will be
// decided by the characters at index r and r - 1
if (res4 == 0) {
if (s[r - 1] > s[r])
res4 = 1;
else if (s[r - 1] < s[r])
res4 = 2;
}
// Check if there is a way such that A can guarantee the
// win
if ((res1 == 1 && res2 == 1)
|| (res3 == 1 && res4 == 1)) {
return dp[l][r] = 1;
}
// Check if there is no way for A to win
if (res1 == 2 && res2 == 2 && res3 == 2 && res4 == 2) {
return dp[l][r] = 2;
}
// Draw
return dp[l][r] = 0;
}
int main()
{
string s = "geek";
int n = s.length();
vector<vector<int> > dp(n, vector<int>(n, -1));
int res = solve(s, 0, n - 1, dp);
if (res == 0)
cout << "Draw\n";
else if (res == 1)
cout << "A\n";
else
cout << "B\n";
return 0;
}
Java
import java.util.Arrays;
public class Main {
// method to find the winner of the game
// return 0 if there is a draw, 1 if A wins and 2 if B wins
static int solve(String s, int l, int r, int[][] dp) {
if (r - l == 1) {
if (s.charAt(l) == s.charAt(r))
return 0;
return 1;
}
if (dp[l][r] != -1) {
return dp[l][r];
}
// A chooses the character at index l and B chooses the
// character at index r
int res1 = solve(s, l + 1, r - 1, dp);
// If the result is a draw then the answer will be
// decided by the characters at index l and r
if (res1 == 0) {
if (s.charAt(l) < s.charAt(r))
res1 = 1;
else if (s.charAt(l) > s.charAt(r))
res1 = 2;
}
// A chooses the character at index l and B chooses the
// character at index l + 1
int res2 = solve(s, l + 2, r, dp);
// If the result is a draw then the answer will be
// decided by the characters at index l and l + 1
if (res2 == 0) {
if (s.charAt(l) < s.charAt(l + 1))
res2 = 1;
else if (s.charAt(l) > s.charAt(l + 1))
res2 = 2;
}
// A chooses the character at index r and B chooses the
// character at index l
int res3 = solve(s, l + 1, r - 1, dp);
// If the result is a draw then the answer will be
// decided by the characters at index l and r
if (res3 == 0) {
if (s.charAt(l) > s.charAt(r))
res3 = 1;
else if (s.charAt(l) < s.charAt(r))
res3 = 2;
}
// A chooses the character at index r and B chooses the
// character at index r - 1
int res4 = solve(s, l, r - 2, dp);
// If the result is a draw then the answer will be
// decided by the characters at index r and r - 1
if (res4 == 0) {
if (s.charAt(r - 1) > s.charAt(r))
res4 = 1;
else if (s.charAt(r - 1) < s.charAt(r))
res4 = 2;
}
// Check if there is a way such that A can guarantee the
// win
if ((res1 == 1 && res2 == 1) || (res3 == 1 && res4 == 1)) {
return dp[l][r] = 1;
}
// Check if there is no way for A to win
if (res1 == 2 && res2 == 2 && res3 == 2 && res4 == 2) {
return dp[l][r] = 2;
}
// Draw
return dp[l][r] = 0;
}
public static void main(String[] args) {
String s = "geek";
int n = s.length();
int[][] dp = new int[n][n];
for (int[] row : dp) {
Arrays.fill(row, -1);
}
int res = solve(s, 0, n - 1, dp);
if (res == 0)
System.out.println("Draw");
else if (res == 1)
System.out.println("A");
else
System.out.println("B");
}
}
// This code is contributed by akshitaguprzj3
C#
using System;
using System.Collections.Generic;
class Program {
// Method to find the winner of the game
// Returns 0 if there is a draw, 1 if A wins, and 2 if B
// wins
static int Solve(string s, int l, int r,
List<List<int> > dp)
{
if (r - l == 1) {
if (s[l] == s[r])
return 0;
return 1;
}
if (dp[l][r] != -1) {
return dp[l][r];
}
// A chooses the character at index l and B chooses
// the character at index r
int res1 = Solve(s, l + 1, r - 1, dp);
// If the result is a draw then the answer will be
// decided by the characters at index l and r
if (res1 == 0) {
if (s[l] < s[r])
res1 = 1;
else if (s[l] > s[r])
res1 = 2;
}
// A chooses the character at index l and B chooses
// the character at index l + 1
int res2 = Solve(s, l + 2, r, dp);
// If the result is a draw then the answer will be
// decided by the characters at index l and l + 1
if (res2 == 0) {
if (s[l] < s[l + 1])
res2 = 1;
else if (s[l] > s[l + 1])
res2 = 2;
}
// A chooses the character at index r and B chooses
// the character at index l
int res3 = Solve(s, l + 1, r - 1, dp);
// If the result is a draw then the answer will be
// decided by the characters at index l and r
if (res3 == 0) {
if (s[l] > s[r])
res3 = 1;
else if (s[l] < s[r])
res3 = 2;
}
// A chooses the character at index r and B chooses
// the character at index r - 1
int res4 = Solve(s, l, r - 2, dp);
// If the result is a draw then the answer will be
// decided by the characters at index r and r - 1
if (res4 == 0) {
if (s[r - 1] > s[r])
res4 = 1;
else if (s[r - 1] < s[r])
res4 = 2;
}
// Check if there is a way such that A can guarantee
// the win
if ((res1 == 1 && res2 == 1)
|| (res3 == 1 && res4 == 1)) {
return dp[l][r] = 1;
}
// Check if there is no way for A to win
if (res1 == 2 && res2 == 2 && res3 == 2
&& res4 == 2) {
return dp[l][r] = 2;
}
// Draw
return dp[l][r] = 0;
}
static void Main(string[] args)
{
string s = "geek";
int n = s.Length;
List<List<int> > dp = new List<List<int> >();
for (int i = 0; i < n; i++) {
dp.Add(new List<int>());
for (int j = 0; j < n; j++) {
dp[i].Add(-1);
}
}
int res = Solve(s, 0, n - 1, dp);
if (res == 0)
Console.WriteLine("Draw");
else if (res == 1)
Console.WriteLine("A");
else
Console.WriteLine("B");
}
}
JavaScript
// Method to find the winner of the game
// Returns 0 if there is a draw, 1 if A wins, and 2 if B wins
function solve(s, l, r, dp) {
if (r - l === 1) {
if (s[l] === s[r])
return 0;
return 1;
}
if (dp[l][r] !== -1) {
return dp[l][r];
}
// A chooses the character at index l and B chooses the
// character at index r
let res1 = solve(s, l + 1, r - 1, dp);
// If the result is a draw then the answer will be
// decided by the characters at index l and r
if (res1 === 0) {
if (s[l] < s[r])
res1 = 1;
else if (s[l] > s[r])
res1 = 2;
}
// A chooses the character at index l and B chooses the
// character at index l + 1
let res2 = solve(s, l + 2, r, dp);
// If the result is a draw then the answer will be
// decided by the characters at index l and l + 1
if (res2 === 0) {
if (s[l] < s[l + 1])
res2 = 1;
else if (s[l] > s[l + 1])
res2 = 2;
}
// A chooses the character at index r and B chooses the
// character at index l
let res3 = solve(s, l + 1, r - 1, dp);
// If the result is a draw then the answer will be
// decided by the characters at index l and r
if (res3 === 0) {
if (s[l] > s[r])
res3 = 1;
else if (s[l] < s[r])
res3 = 2;
}
// A chooses the character at index r and B chooses the
// character at index r - 1
let res4 = solve(s, l, r - 2, dp);
// If the result is a draw then the answer will be
// decided by the characters at index r and r - 1
if (res4 === 0) {
if (s[r - 1] > s[r])
res4 = 1;
else if (s[r - 1] < s[r])
res4 = 2;
}
// Check if there is a way such that A can guarantee the
// win
if ((res1 === 1 && res2 === 1)
|| (res3 === 1 && res4 === 1)) {
return dp[l][r] = 1;
}
// Check if there is no way for A to win
if (res1 === 2 && res2 === 2 && res3 === 2 && res4 === 2) {
return dp[l][r] = 2;
}
// Draw
return dp[l][r] = 0;
}
function main() {
let s = "geek";
let n = s.length;
let dp = new Array(n).fill(null).map(() => new Array(n).fill(-1));
let res = solve(s, 0, n - 1, dp);
if (res === 0)
console.log("Draw");
else if (res === 1)
console.log("A");
else
console.log("B");
}
main();
Python3
# Python Implementation
# method to find the winner of the game
# return 0 if there is a draw, 1 if A wins and 2 if B wins
def solve(s, l, r, dp):
if r - l == 1:
if s[l] == s[r]:
return 0
return 1
if dp[l][r] != -1:
return dp[l][r]
# A chooses the character at index l and B chooses the
# character at index r
res1 = solve(s, l + 1, r - 1, dp)
# If the result is a draw then the answer will be
# decided by the characters at index l and r
if res1 == 0:
if s[l] < s[r]:
res1 = 1
elif s[l] > s[r]:
res1 = 2
# A chooses the character at index l and B chooses the
# character at index l + 1
res2 = solve(s, l + 2, r, dp)
# If the result is a draw then the answer will be
# decided by the characters at index l and l + 1
if res2 == 0:
if s[l] < s[l + 1]:
res2 = 1
elif s[l] > s[l + 1]:
res2 = 2
# A chooses the character at index r and B chooses the
# character at index l
res3 = solve(s, l + 1, r - 1, dp)
# If the result is a draw then the answer will be
# decided by the characters at index l and r
if res3 == 0:
if s[l] > s[r]:
res3 = 1
elif s[l] < s[r]:
res3 = 2
# A chooses the character at index r and B chooses the
# character at index r - 1
res4 = solve(s, l, r - 2, dp)
# If the result is a draw then the answer will be
# decided by the characters at index r and r - 1
if res4 == 0:
if s[r - 1] > s[r]:
res4 = 1
elif s[r - 1] < s[r]:
res4 = 2
# Check if there is a way such that A can guarantee the
# win
if (res1 == 1 and res2 == 1) or (res3 == 1 and res4 == 1):
dp[l][r] = 1
return 1
# Check if there is no way for A to win
if res1 == 2 and res2 == 2 and res3 == 2 and res4 == 2:
dp[l][r] = 2
return 2
# Draw
dp[l][r] = 0
return 0
if __name__ == "__main__":
s = "geek"
n = len(s)
dp = [[-1 for _ in range(n)] for _ in range(n)]
res = solve(s, 0, n - 1, dp)
if res == 0:
print("Draw")
elif res == 1:
print("A")
else:
print("B")
# This code is contributed by Tapesh(tapeshdu420)
Time Complexity: O(N * N), where N is the length of the input string S.
Auxiliary Space: O(N * N)
Similar Reads
Lexicographically smallest String by removing exactly K characters Given a string s consisting of only lowercase characters, the task is to find the lexicographically smallest string after removing exactly k characters from the string. But you have to modify the value of k, i.e., if the length of the string is a power of 2, reduce k by half, else multiply k by 2. Y
15 min read
Lexicographically smallest String formed by extracting single character Given a string array S, the task is to find the lexicographically smallest string that can be formed by extracting a single character in each string from the string array S. Example: Input: S = ["xy", "fd"]Output: "dx"Explanation: The possible strings formed by extracting a single character from eac
5 min read
Lexicographically smallest string formed by removing at most one character Given a string s, the task is to find the lexicographically smallest string that can be formed by removing at most one character from the given string. Examples: Input: s = "abcda" Output: "abca"Explanation: One can remove 'd' to get "abca" which is the lexicographically smallest string possible. In
4 min read
Lexicographically smallest string formed by removing duplicates Given a string S consisting of lowercase alphabets, the task is to find the lexicographically smallest string that can be obtained by removing duplicates from the given string S. Examples: Input: S = "yzxyz"Output: xyzExplanation: Removing the duplicate characters at indices 0 and 1 in the given str
7 min read
Maximum occurring lexicographically smallest character in a String Given a string containing lowercase characters. The task is to print the maximum occurring character in the input string. If 2 or more characters appear the same number of times, print the lexicographically (alphabetically) lowest (first) character. Examples: Input: test sample Output: e Explanation
6 min read