Change Minimum Characters to Satisfy One of Three Conditions solution and explanation
7 more videos on this problem
LeetCode 1737. Change Minimum Characters to Satisfy One of Three ConditionsHappy Coding · 19:03 · 1K views
Leetcode Weekly Contest 225 | PROBLEM 1736 , 1737 | BITS PILANIcode Explainer · 10:29 · 1K views
Leetcode 1737. Change Minimum Characters to Satisfy One of Three ConditionsLeetcoder · 7:40 · 927 views
Leetcode 1737. Change Minimum Characters to Satisfy One of Three ConditionsFraz · 9:12 · 892 views
【每日一题】1737. Change Minimum Characters to Satisfy One of Three Conditions, 1/25/2021Huifeng Guan · 12:46 · 432 views
1737. Change Minimum Characters to Satisfy One of Three Conditions (Leetcode Medium)Programming Live with Larry · 43:46 · 288 views
Leetcode--1737 change minimum characters to satisfy one of three conditions (Greedy)You Wu · 17:16 · 125 views
LeetCode 1737: Change Minimum Characters to Satisfy One of Three ConditionsAlitaCode · 29:40 · 3 views
The problem
You are given two strings a and b that consist of lowercase letters. In one operation, you can change any character in a or b to any lowercase letter.
Your goal is to satisfy one of the following three conditions:
- Every letter in
ais strictly less than every letter inbin the alphabet. - Every letter in
bis strictly less than every letter inain the alphabet. - Both
aandbconsist of only one distinct letter.
Return the minimum number of operations needed to achieve your goal.
Example 1:
Input: a = "aba", b = "caa" Output: 2 Explanation: Consider the best way to make each condition true: 1) Change b to "ccc" in 2 operations, then every letter in a is less than every letter in b. 2) Change a to "bbb" and b to "aaa" in 3 operations, then every letter in b is less than every letter in a. 3) Change a to "aaa" and b to "aaa" in 2 operations, then a and b consist of one distinct letter. The best way was done in 2 operations (either condition 1 or condition 3).
Example 2:
Input: a = "dabadd", b = "cda" Output: 3 Explanation: The best way is to make condition 1 true by changing b to "eee".
Constraints:
1 <= a.length, b.length <= 105aandbconsist only of lowercase letters.
Approach overview
Problem Overview: You get two lowercase strings a and b. Modify the minimum number of characters so one of three conditions holds: every character in a is strictly less than every character in b, every character in b is strictly less than every character in a, or both strings contain only one distinct character.
The constraints are small for the alphabet (26 letters) but large for string length. That means the right strategy focuses on frequency counting instead of comparing characters directly.
Approach 1: Direct Count and Compare (O(n + 26), space O(26))
Start by building two frequency arrays of size 26 for a and b. Each index represents a letter from 'a' to 'z'. With these counts, evaluate the three required conditions.
For the third condition (both strings use a single identical character), iterate through all 26 letters and compute how many characters must change so both strings become that letter. The minimum across all letters is the cost.
For the first two conditions, test every possible split character c where letters in one string must be <= c and the other > c. Count how many characters violate this rule using the frequency arrays. This approach relies on simple counting and works well because the alphabet size is constant.
Approach 2: Prefix Sums for Strictly Less Condition (O(n + 26), space O(26))
This approach improves the evaluation of lexicographic conditions using prefix sums over the frequency arrays. After counting characters, build prefix sums where prefix[i] stores the number of characters with index ≤ i.
For a split character i, you instantly know how many characters in a are ≤ i and how many in b are ≤ i. From this you derive how many characters violate the strictly less requirement. Iterate over all 25 possible split points (a–y) and compute the required modifications.
Prefix sums remove repeated counting work and make the condition checks constant time per letter. The total complexity stays linear in the string length.
Both strategies rely heavily on character frequencies, making them classic applications of counting and prefix sum techniques on string data.
Recommended for interviews: The prefix-sum counting approach. Interviewers expect you to reduce the problem to frequency arrays over the 26-letter alphabet and evaluate split points efficiently. Starting with direct counting shows understanding, but using prefix sums demonstrates stronger algorithmic thinking.
Approach 1: Prefix Sums for Strictly Less Condition
This approach uses prefix sums to efficiently calculate the minimum operations required to make all letters in one string strictly less than all letters in the other string. The essential idea is to transform frequency counts into cumulative counts (prefix sums) to get faster comparisons between possible transformation states.
def min_operations(a: str, b: str) -> int:
freq_a = [0] * 26
freq_b = [0] * 26
for char in a:
freq_a[ord(char) - ord('a')] += 1
for char in b:
freq_b[ord(char) - ord('a')] += 1
# Prefix sums
for i in range(1, 26):
freq_a[i] += freq_a[i - 1]
freq_b[i] += freq_b[i - 1]
# Calculating minimum operations
n, m = len(a), len(b)
best = float('inf')
# Make every letter in a strictly less than every letter in b
for i in range(25):
best = min(best, (n - freq_a[i]) + (freq_b[i]))
# Make every letter in b strictly less than every letter in a
for i in range(25):
best = min(best, (m - freq_b[i]) + (freq_a[i]))
# Make a and b consist of only one distinct letter
best = min(best, n + m - max(freq_a), n + m - max(freq_b))
return bestfunction minOperations(a, b) {
const freqA = Array(26).fill(0);
const freqB = Array(26).fill(0);
for (let char of a) {
freqA[char.charCodeAt(0) - 97] += 1;
}
for (let char of b) {
freqB[char.charCodeAt(0) - 97] += 1;
}
let n = a.length, m = b.length;
for (let i = 1; i < 26; i++) {
freqA[i] += freqA[i-1];
freqB[i] += freqB[i-1];
}
let best = Infinity;
// Condition 1 and 2
for (let i = 0; i < 25; i++) {
best = Math.min(best, n - freqA[i] + freqB[i], m - freqB[i] + freqA[i]);
}
// Condition 3
best = Math.min(best, n + m - Math.max(...freqA), n + m - Math.max(...freqB));
return best;
}The function calculates the frequency of each character in the input strings a and b. It then turns these frequencies into prefix sums. By using prefix sums, we can efficiently calculate how many characters need to change to satisfy the first two conditions: making a strictly less than b or b strictly less than a.
Time Complexity: O(n + m), where n is the length of a and m is the length of b, since we loop over each string to build frequency counts and prefix sums.
Space Complexity: O(1), since the space used is constant and not dependent on the input size.
Approach 2: Direct Count and Compare
This approach works by directly counting the necessary transformations. We evaluate each transformation possibility directly by counting how many elements need to change to satisfy each of the conditions.
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
int minOperations(string a, string b) {
vector<int> freqA(26, 0), freqB(26, 0);
for (char c : a) ++freqA[c - 'a'];
for (char c : b) ++freqB[c - 'a'];
int operations = INT_MAX, n = a.size(), m = b.size();
for (int i = 0; i < 26; ++i) {
if (i > 0) {
freqA[i] += freqA[i - 1];
freqB[i] += freqB[i - 1];
}
if (i < 25) {
operations = min(operations, n - freqA[i] + freqB[i]);
operations = min(operations, m - freqB[i] + freqA[i]);
}
}
operations = min(operations, n + m - *max_element(freqA.begin(), freqA.end()));
operations = min(operations, n + m - *max_element(freqB.begin(), freqB.end()));
return operations;
}using System;
using System.Linq;
class Solution {
public int MinOperations(string a, string b) {
int[] freqA = new int[26];
int[] freqB = new int[26];
foreach (char c in a) freqA[c - 'a']++;
foreach (char c in b) freqB[c - 'a']++;
int n = a.Length, m = b.Length, best = int.MaxValue;
for (int i = 0; i < 26; i++) {
if (i > 0) {
freqA[i] += freqA[i - 1];
freqB[i] += freqB[i - 1];
}
if (i < 25) {
best = Math.Min(best, n - freqA[i] + freqB[i]);
best = Math.Min(best, m - freqB[i] + freqA[i]);
}
}
best = Math.Min(best, n + m - freqA.Max());
best = Math.Min(best, n + m - freqB.Max());
return best;
}
}By using integer arrays to count and partially sum frequencies, we evaluate all feasible character transformations to reach the desired string states. We directly compute the changes needed to make all elements in 'a' less than 'b' or vice versa, or to make both uniform strings.
Time Complexity: O(n + m).
Space Complexity: O(1).
Approach 3: Counting + Enumeration
First, we count the number of occurrences of each letter in strings a and b, denoted as cnt_1 and cnt_2.
Then, we consider condition 3, i.e., every letter in a and b is the same. We just need to enumerate the final letter c, and then count the number of letters in a and b that are not c. This is the number of characters that need to be changed.
Next, we consider conditions 1 and 2, i.e., every letter in a is less than every letter in b, or every letter in b is less than every letter in a. For condition 1, we make all characters in string a less than character c, and all characters in string b not less than c. We enumerate c to find the smallest answer. Condition 2 is similar.
The final answer is the minimum of the above three cases.
The time complexity is O(m + n + C^2), where m and n are the lengths of strings a and b respectively, and C is the size of the character set. In this problem, C = 26.
class Solution {
private int ans;
public int minCharacters(String a, String b) {
int m = a.length(), n = b.length();
int[] cnt1 = new int[26];
int[] cnt2 = new int[26];
for (int i = 0; i < m; ++i) {
++cnt1[a.charAt(i) - 'a'];
}
for (int i = 0; i < n; ++i) {
++cnt2[b.charAt(i) - 'a'];
}
ans = m + n;
for (int i = 0; i < 26; ++i) {
ans = Math.min(ans, m + n - cnt1[i] - cnt2[i]);
}
f(cnt1, cnt2);
f(cnt2, cnt1);
return ans;
}
private void f(int[] cnt1, int[] cnt2) {
for (int i = 1; i < 26; ++i) {
int t = 0;
for (int j = i; j < 26; ++j) {
t += cnt1[j];
}
for (int j = 0; j < i; ++j) {
t += cnt2[j];
}
ans = Math.min(ans, t);
}
}
}function minCharacters(a: string, b: string): number {
const m = a.length,
n = b.length;
let count1 = new Array(26).fill(0);
let count2 = new Array(26).fill(0);
const base = 'a'.charCodeAt(0);
for (let char of a) {
count1[char.charCodeAt(0) - base]++;
}
for (let char of b) {
count2[char.charCodeAt(0) - base]++;
}
let pre1 = 0,
pre2 = 0;
let ans = m + n;
for (let i = 0; i < 25; i++) {
pre1 += count1[i];
pre2 += count2[i];
// case1, case2, case3
ans = Math.min(ans, m - pre1 + pre2, pre1 + n - pre2, m + n - count1[i] - count2[i]);
}
ans = Math.min(ans, m + n - count1[25] - count2[25]);
return ans;
}func minCharacters(a string, b string) int {
cnt1 := [26]int{}
cnt2 := [26]int{}
for _, c := range a {
cnt1[c-'a']++
}
for _, c := range b {
cnt2[c-'a']++
}
m, n := len(a), len(b)
ans := m + n
for i := 0; i < 26; i++ {
ans = min(ans, m+n-cnt1[i]-cnt2[i])
}
f := func(cnt1, cnt2 [26]int) {
for i := 1; i < 26; i++ {
t := 0
for j := i; j < 26; j++ {
t += cnt1[j]
}
for j := 0; j < i; j++ {
t += cnt2[j]
}
ans = min(ans, t)
}
}
f(cnt1, cnt2)
f(cnt2, cnt1)
return ans
}Complexity comparison
| Approach | Complexity |
|---|---|
| Prefix Sums for Strictly Less Condition | Time Complexity: O(n + m), where n is the length of a and m is the length of b, since we loop over each string to build frequency counts and prefix sums. Space Complexity: O(1), since the space used is constant and not dependent on the input size. |
| Direct Count and Compare | Time Complexity: O(n + m). Space Complexity: O(1). |
| Counting + Enumeration | – |
Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Direct Count and Compare | O(n + 26) | O(26) | Simple implementation when using frequency arrays to evaluate all conditions directly. |
| Prefix Sums for Strictly Less Condition | O(n + 26) | O(26) | Preferred approach when efficiently evaluating lexicographic split points using cumulative counts. |
Frequently asked questions
Is Change Minimum Characters to Satisfy One of Three Conditions easy or hard?
The problem is rated Medium because the brute idea is simple but recognizing the frequency-count strategy is key. Once you model the strings as 26-length count arrays and test alphabet split points, the solution becomes a clean linear-time algorithm.
Change Minimum Characters to Satisfy One of Three Conditions Python/Java solution
Implementations typically build two frequency arrays and optionally prefix sums. Then iterate through alphabet split points and compute modification counts. The logic is straightforward to implement in Python, JavaScript, C++, or C#, since it relies only on arrays and simple arithmetic.
How to solve Change Minimum Characters to Satisfy One of Three Conditions in O(n)?
First count the frequency of each character in both strings using arrays of size 26. Build prefix sums to quickly determine how many characters are ≤ a chosen letter. Iterate through every possible split letter and compute how many characters must change to satisfy the lexicographic rules. Track the minimum changes across all splits and the single-character condition.
What is the best approach for Change Minimum Characters to Satisfy One of Three Conditions?
The optimal solution uses frequency counting combined with prefix sums over the 26 lowercase letters. After counting characters in both strings, iterate through possible split characters to evaluate the lexicographic conditions. Prefix sums allow constant-time checks for each split, giving an overall time complexity of O(n + 26) and space complexity of O(26).
Is Change Minimum Characters to Satisfy One of Three Conditions asked at Google/Amazon/Meta?
Problems involving character frequency counting and lexicographic constraints frequently appear in interviews at companies like Google, Amazon, and Meta. This problem tests understanding of counting arrays, prefix sums, and how to transform strings efficiently under constraints.
What data structure is used in Change Minimum Characters to Satisfy One of Three Conditions?
The key data structures are fixed-size frequency arrays (size 26) for lowercase letters and prefix sum arrays derived from them. These allow constant-time queries about how many characters fall within certain alphabet ranges.
What is the time complexity of Change Minimum Characters to Satisfy One of Three Conditions?
The optimal time complexity is O(n + 26), where n is the combined length of the two strings. Counting characters takes O(n), and evaluating all alphabet split points takes O(26). Since the alphabet size is constant, the algorithm effectively runs in linear time.
