Find Winner of Flip Game II
Last Updated :
16 Apr, 2024
Given a string currentState that contains only ‘+’ and ‘-‘. You and your friend take turns to flip two consecutive “++” into “–“. The game ends when a person can no longer make a move. The task is to return true if the starting player can guarantee a win, and false otherwise.
Examples:
Input: s = “++++”
Output: true
Explanation: Player ‘A’ can guarantee a win by converting the middle “11” to become “1001”.
Input: s = “+”
Output: false
Approach:
Iterating through the string and trying all possible moves. For each “++” convert it to “–” and store this move using bit masking, in this case if we are changing (i -1)th and (i)th bit of 1 to 0 then we set bit into our mask at this position. This mask will help us to not make same move again. Then recursively call to check if the second player can win from the resulting state. If the second player cannot win, it means the first player can guarantee a win by making this move.
Steps-by-step approach:
- Create a recursive function findWinnerHelper() to checks if the first player can win by exploring different moves.
- Memoization (dp map) is used to store results of previously explored states to avoid redundant computations.
- Iterate through the string to find consecutive ‘+’s.
- If consecutive ‘1‘s are found, make a move by converting them to ‘-’.
- Convert the current state to a binary representation and check the next state recursively.
- Undo the move for backtracking to explore other possibilities.
- Memoize the result for the current state to avoid recomputation.
- The findWinner() function initializes the memoization map and calls the helper function findWinnerHelper() with the initial state.
- The result is printed based on whether ‘A‘ or ‘B‘ wins.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
// Recursive helper function to check if the first player
// can win the game
bool findWinnerHelper(string s, long convertState,
unordered_map<long, bool>& dp)
{
// Check if the result for the current state is already
// memoized
if (dp.find(convertState) != dp.end()) {
return dp[convertState];
}
// Iterate through the string to find consecutive '1's
for (int i = 1; i < s.length(); i++) {
if (s[i] == '+' && s[i - 1] == '+') {
// Flip the signs for a potential winning move
s[i] = '-';
s[i - 1] = '-';
// Convert the current state to a binary
// representation
long nextState = convertState | (1 << i);
nextState = nextState | (1 << (i - 1));
// Recursively check if the next player can win
// after the move
if (!findWinnerHelper(s, nextState, dp)) {
// If the next player cannot win, memoize
// and return true
dp[convertState] = true;
s[i] = '+';
s[i - 1] = '+';
return true;
}
// Undo the move for backtracking
s[i] = '+';
s[i - 1] = '+';
}
}
// Memoize the result if no winning move is found
dp[convertState] = false;
return false;
}
// Main function to check if the first player can win
bool findWinner(string s)
{
unordered_map<long, bool> dp;
return findWinnerHelper(s, 0, dp);
}
int main()
{
// Example test case
string s = "++++";
bool result = findWinner(s);
// Output the result
cout << (result ? "True" : "False") << endl;
return 0;
}
Java
import java.util.*;
public class FirstPlayerWinner {
// Recursive helper function to check if the first player can win the game
static boolean findWinnerHelper(String s, long convertState, Map<Long, Boolean> dp) {
// Check if the result for the current state is already memoized
if (dp.containsKey(convertState)) {
return dp.get(convertState);
}
// Iterate through the string to find consecutive '++'s
for (int i = 1; i < s.length(); i++) {
if (s.charAt(i) == '+' && s.charAt(i - 1) == '+') {
// Flip the signs for a potential winning move
char[] chars = s.toCharArray();
chars[i] = '-';
chars[i - 1] = '-';
s = String.valueOf(chars);
// Convert the current state to a binary representation
long nextState = convertState | (1L << i);
nextState = nextState | (1L << (i - 1));
// Recursively check if the next player can win after the move
if (!findWinnerHelper(s, nextState, dp)) {
// If the next player cannot win, memoize and return true
dp.put(convertState, true);
chars[i] = '+';
chars[i - 1] = '+';
s = String.valueOf(chars);
return true;
}
// Undo the move for backtracking
chars[i] = '+';
chars[i - 1] = '+';
s = String.valueOf(chars);
}
}
// Memoize the result if no winning move is found
dp.put(convertState, false);
return false;
}
// Main function to check if the first player can win
static boolean findWinner(String s) {
Map<Long, Boolean> dp = new HashMap<>();
return findWinnerHelper(s, 0, dp);
}
public static void main(String[] args) {
// Example test case
String s = "++++";
boolean result = findWinner(s);
// Output the result
System.out.println(result ? "True" : "False");
}
}
Python3
# Recursive helper function to check if the first player
# can win the game
def find_winner_helper(s, convert_state, dp):
# Check if the result for the current state is already
# memoized
if convert_state in dp:
return dp[convert_state]
# Iterate through the string to find consecutive '1's
for i in range(1, len(s)):
if s[i] == '+' and s[i - 1] == '+':
# Flip the signs for a potential winning move
s = s[:i] + '-' + s[i + 1:]
s = s[:i - 1] + '-' + s[i:]
# Convert the current state to a binary
# representation
next_state = convert_state | (1 << i)
next_state |= (1 << (i - 1))
# Recursively check if the next player can win
# after the move
if not find_winner_helper(s, next_state, dp):
# If the next player cannot win, memoize
# and return True
dp[convert_state] = True
s = s[:i] + '+' + s[i + 1:]
s = s[:i - 1] + '+' + s[i:]
return True
# Undo the move for backtracking
s = s[:i] + '+' + s[i + 1:]
s = s[:i - 1] + '+' + s[i:]
# Memoize the result if no winning move is found
dp[convert_state] = False
return False
# Main function to check if the first player can win
def find_winner(s):
dp = {}
return find_winner_helper(s, 0, dp)
# Example test case
s = "++++"
result = find_winner(s)
# Output the result
print("True" if result else "False")
JavaScript
function findWinnerHelper(s, convertState, dp) {
// Check if the result for the current state is already memoized
if (dp[convertState] !== undefined) {
return dp[convertState];
}
// Iterate through the string to find consecutive '+'s
for (let i = 1; i < s.length; i++) {
if (s[i] === '+' && s[i - 1] === '+') {
// Flip the signs for a potential winning move
let nextState = convertState | (1 << i);
nextState |= (1 << (i - 1));
// Recursively check if the next player can win after the move
if (!findWinnerHelper(s.substring(0, i - 1) + '-' + s.substring(i - 1 + 2), nextState, dp)) {
// If the next player cannot win, memoize and return true
dp[convertState] = true;
return true;
}
}
}
// Memoize the result if no winning move is found
dp[convertState] = false;
return false;
}
// Main function to check if the first player can win
function findWinner(s) {
const dp = {};
return findWinnerHelper(s, 0, dp);
}
// Example test case
const s = "++++";
const result = findWinner(s);
// Output the result
console.log(result ? "True" : "False");
Time Complexity: O(n), where n is the length of the input string.
Auxiliary Space: O(n), where n is the length of the input string.
Share your thoughts in the comments
Please Login to comment...