Using greedy without proof
Wrong move: Locally optimal choices may fail globally.
Usually fails on: Counterexamples appear on crafted input orderings.
Fix: Verify with exchange argument or monotonic objective before committing.
Build confidence with an intuition-first walkthrough focused on greedy fundamentals.
Given a string s containing only digits, return the lexicographically smallest string that can be obtained after swapping adjacent digits in s with the same parity at most once.
Digits have the same parity if both are odd or both are even. For example, 5 and 9, as well as 2 and 4, have the same parity, while 6 and 9 do not.
Example 1:
Input: s = "45320"
Output: "43520"
Explanation:
s[1] == '5' and s[2] == '3' both have the same parity, and swapping them results in the lexicographically smallest string.
Example 2:
Input: s = "001"
Output: "001"
Explanation:
There is no need to perform a swap because s is already the lexicographically smallest.
Constraints:
2 <= s.length <= 100s consists only of digits.Problem summary: Given a string s containing only digits, return the lexicographically smallest string that can be obtained after swapping adjacent digits in s with the same parity at most once. Digits have the same parity if both are odd or both are even. For example, 5 and 9, as well as 2 and 4, have the same parity, while 6 and 9 do not.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Greedy
"45320"
"001"
lexicographically-smallest-string-after-applying-operations)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #3216: Lexicographically Smallest String After a Swap
class Solution {
public String getSmallestString(String s) {
char[] cs = s.toCharArray();
int n = cs.length;
for (int i = 1; i < n; ++i) {
char a = cs[i - 1], b = cs[i];
if (a > b && a % 2 == b % 2) {
cs[i] = a;
cs[i - 1] = b;
return new String(cs);
}
}
return s;
}
}
// Accepted solution for LeetCode #3216: Lexicographically Smallest String After a Swap
func getSmallestString(s string) string {
cs := []byte(s)
n := len(cs)
for i := 1; i < n; i++ {
a, b := cs[i-1], cs[i]
if a > b && a%2 == b%2 {
cs[i-1], cs[i] = b, a
return string(cs)
}
}
return s
}
# Accepted solution for LeetCode #3216: Lexicographically Smallest String After a Swap
class Solution:
def getSmallestString(self, s: str) -> str:
for i, (a, b) in enumerate(pairwise(map(ord, s))):
if (a + b) % 2 == 0 and a > b:
return s[:i] + s[i + 1] + s[i] + s[i + 2 :]
return s
// Accepted solution for LeetCode #3216: Lexicographically Smallest String After a Swap
impl Solution {
pub fn get_smallest_string(s: String) -> String {
let mut cs: Vec<u8> = s.into_bytes();
let n = cs.len();
for i in 1..n {
let (a, b) = (cs[i - 1], cs[i]);
if a > b && a % 2 == b % 2 {
cs.swap(i - 1, i);
return String::from_utf8(cs).unwrap();
}
}
String::from_utf8(cs).unwrap()
}
}
// Accepted solution for LeetCode #3216: Lexicographically Smallest String After a Swap
function getSmallestString(s: string): string {
const n = s.length;
const cs: string[] = s.split('');
for (let i = 1; i < n; ++i) {
const a = cs[i - 1];
const b = cs[i];
if (a > b && +a % 2 === +b % 2) {
cs[i - 1] = b;
cs[i] = a;
return cs.join('');
}
}
return s;
}
Use this to step through a reusable interview workflow for this problem.
Try every possible combination of choices. With n items each having two states (include/exclude), the search space is 2ⁿ. Evaluating each combination takes O(n), giving O(n × 2ⁿ). The recursion stack or subset storage uses O(n) space.
Greedy algorithms typically sort the input (O(n log n)) then make a single pass (O(n)). The sort dominates. If the input is already sorted or the greedy choice can be computed without sorting, time drops to O(n). Proving greedy correctness (exchange argument) is harder than the implementation.
Review these before coding to avoid predictable interview regressions.
Wrong move: Locally optimal choices may fail globally.
Usually fails on: Counterexamples appear on crafted input orderings.
Fix: Verify with exchange argument or monotonic objective before committing.