LeetCode 2546 - Apply Bitwise Operations to Make Strings Equal
The problem provides two binary strings, s and target, of equal length n. You are allowed to perform a specific bitwise operation on s any number of times, which involves picking two distinct indices i and j and updating s[i] to s[i] OR s[j] and s[j] to s[i] XOR s[j].
Difficulty: 🟡 Medium
Topics: String, Bit Manipulation
Solution
Problem Understanding
The problem provides two binary strings, s and target, of equal length n. You are allowed to perform a specific bitwise operation on s any number of times, which involves picking two distinct indices i and j and updating s[i] to s[i] OR s[j] and s[j] to s[i] XOR s[j]. The goal is to determine whether it is possible to transform s into target using this operation.
In simpler terms, you need to check if, by repeatedly combining and swapping bits in s using OR and XOR operations, you can make every bit of s exactly match target. The input strings only contain '0' or '1', and the length can go up to 100,000, so a naive simulation of all operations is impractical.
Key observations from the constraints are that the operation preserves the total number of '1's in a certain sense: if s contains no '1's but target does, the transformation is impossible. The problem also guarantees both strings have length at least 2, which ensures operations involving two indices are always feasible.
Important edge cases include strings with all zeros, strings with all ones, strings with mismatched presence of ones, or strings that are already equal.
Approaches
The brute-force approach would attempt to simulate all possible pairs (i, j) and perform the operation repeatedly until s matches target or no progress can be made. This approach is correct in theory but infeasible for large n because the number of possible operations grows quadratically with the string length and can lead to exponential sequences of operations.
The optimal approach relies on a crucial observation: the operation allows you to propagate '1's across s but cannot create new '1's if none exist. Therefore, the only condition that prevents transformation is if target contains '1' but s has none. Conversely, if s contains at least one '1', it is always possible to spread it and manipulate s to match any target.
This insight reduces the problem to a simple check for the existence of at least one '1' in s if target contains any '1'. No full simulation is needed.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n^2) | O(n) | Simulate all operations for all index pairs; too slow for n up to 10^5 |
| Optimal | O(n) | O(1) | Check presence of '1' in s and target; simple and efficient |
Algorithm Walkthrough
- Scan the string
targetto check if it contains at least one '1'. This is necessary because iftargetis all zeros, we must ensurescan also become all zeros. - Scan the string
sto check if it contains at least one '1'. This tells us whether we can propagate '1's ins. - If
targetcontains a '1' butscontains no '1's, returnfalseimmediately because it is impossible to create new '1's. - Otherwise, return
truebecause we can transformsintotargetusing the allowed operations.
Why it works: The operation allows '1's to be propagated to any position via repeated OR/XOR updates. If there is at least one '1' in s, you can eventually reach any configuration of target. If s has no '1's, you cannot create a '1', so any '1' in target makes transformation impossible.
Python Solution
class Solution:
def makeStringsEqual(self, s: str, target: str) -> bool:
# Check if target has at least one '1'
target_has_one = '1' in target
# Check if s has at least one '1'
s_has_one = '1' in s
# If target has '1' but s has none, impossible
if target_has_one and not s_has_one:
return False
return True
The Python implementation directly implements the algorithm. It first checks for the presence of '1' in both strings using the in operator. If target requires at least one '1' but s has none, the function returns False; otherwise, it returns True.
Go Solution
func makeStringsEqual(s string, target string) bool {
targetHasOne := false
sHasOne := false
// Check target for '1'
for i := 0; i < len(target); i++ {
if target[i] == '1' {
targetHasOne = true
break
}
}
// Check s for '1'
for i := 0; i < len(s); i++ {
if s[i] == '1' {
sHasOne = true
break
}
}
// If target requires '1' but s has none, impossible
if targetHasOne && !sHasOne {
return false
}
return true
}
In Go, we iterate over the string as a slice of bytes to check for '1's. The logic mirrors Python's but uses explicit loops since Go does not have a built-in in operator for strings.
Worked Examples
Example 1: s = "1010", target = "0110"
| Step | Action | s state | target state |
|---|---|---|---|
| 1 | Check target for '1' | 1010 | 0110 |
| 2 | Check s for '1' | 1010 | 0110 |
| 3 | Both have '1' | 1010 | 0110 |
| 4 | Return True | 1010 | 0110 |
Example 2: s = "11", target = "00"
| Step | Action | s state | target state |
|---|---|---|---|
| 1 | Check target for '1' | 11 | 00 |
| 2 | Check s for '1' | 11 | 00 |
| 3 | Target has no '1', s has '1' | 11 | 00 |
| 4 | Return True | 11 | 00 |
Example 3: s = "00", target = "11"
| Step | Action | s state | target state |
|---|---|---|---|
| 1 | Check target for '1' | 00 | 11 |
| 2 | Check s for '1' | 00 | 11 |
| 3 | Target has '1', s has none | 00 | 11 |
| 4 | Return False | 00 | 11 |
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n) | Single scan of both strings to check for '1', each of length n |
| Space | O(1) | Only a few boolean flags are used, no extra data structures |
The complexity is dominated by linear scanning of the strings. No extra storage is needed, so space complexity is constant.
Test Cases
# Provided examples
assert Solution().makeStringsEqual("1010", "0110") == True # Example 1
assert Solution().makeStringsEqual("11", "00") == True # Example 2
assert Solution().makeStringsEqual("00", "11") == False # Example 3
# Boundary values
assert Solution().makeStringsEqual("0"*100000, "0"*100000) == True # All zeros
assert Solution().makeStringsEqual("1"*100000, "1"*100000) == True # All ones
assert Solution().makeStringsEqual("0"*99999 + "1", "1"*100000) == True # Single one in s
# Mixed cases
assert Solution().makeStringsEqual("010101", "101010") == True
assert Solution().makeStringsEqual("000", "001") == False
| Test | Why |
|---|---|
| "1010", "0110" | Standard case with mix of ones and zeros |
| "11", "00" | Target has no ones, should return True |
| "00", "11" | Target has ones but s has none, impossible |
| 100000 zeros | Large input, edge case |
| 100000 ones | Large input, should succeed |
| Single one at end | Propagation of '1' possible |
| Alternating bits | Mixed propagation scenario |
| Small zeros vs one | Small impossible case |
Edge Cases
The first edge case is when s contains no '1's but target does. This is a failure case because no operations can generate a '1'. The implementation explicitly checks for this scenario and returns False.
The second edge case is when target contains no '1's. Regardless of how many '1's s contains, the transformation is always possible because OR/XOR operations can reduce the bits to zero if needed. The algorithm handles this by simply returning True if target has no '1's.
The third edge case is very large input strings, up to the constraint of 10^5 characters. A naive simulation would be prohibitively slow, but the optimal solution works efficiently because it only