Skip to content

Latest commit

 

History

History

1737

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 

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 a is strictly less than every letter in b in the alphabet.
  • Every letter in b is strictly less than every letter in a in the alphabet.
  • Both a and b consist 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 <= 105
  • a and b consist only of lowercase letters.

Related Topics:
String, Greedy

Solution 1.

// OJ: https://leetcode.com/problems/change-minimum-characters-to-satisfy-one-of-three-conditions/
// Author: github.com/lzl124631x
// Time: O(A + B)
// Space: O(1)
class Solution {
    int count(string &a, string &b) { // make all chars in `b` strictly greater than `a`.
        int ans = INT_MAX; 
        for (char c = 'a'; c < 'z'; ++c) { // assume `c` is the breakpoint -- make all chars in `a` <= `c` and all chars in `b` > `c`
            int cnt = 0;
            for (char x : a) cnt += x > c; // all the chars in `a` that `> c` should be changed.
            for (char x : b) cnt += x <= c; // all the chars in `b` that `<= c` should be changed.
            ans = min(ans, cnt);
        }
        return ans;
    }
public:
    int minCharacters(string a, string b) {
        int x = count(a, b), y = count(b, a); // try operation 1 and 2.
        int ans = INT_MAX;
        for (char c = 'a'; c <= 'z'; ++c) { // try operation 3. Assume we change all chars to `c`
            int cnt = 0;
            for (char x : a) cnt += x != c;
            for (char x : b) cnt += x != c;
            ans = min(ans, cnt);
        }
        return min({ x, y, ans });
    }
};

Solution 2.

Use ca and cb to store the frequence of characters in a and b respectively.

We can try each character in [a, z] and use it as a break point.

Take operation 1 for example, if we use 'a' + 2 = 'c' as a break point, that is, changing all a[i] > 'c' to 'c' and changing all b[i] <= 'c' to 'd'.

The count of required operations is op1[2] = SUM(ca, 3, 25) + SUM(cb, 0, 2) where SUM(arr, i, j) = arr[i] + arr[i + 1] + ... + arr[j].

So op1[i] = SUM(ca, i + 1, 25) + SUM(cb, 0, i) where 0 <= i < 25.

op1[i] - op1[i - 1] = cb[i] - ca[i]

Similarly op2[i] = SUM(cb, i + 1, 25) + SUM(ca, 0, i) where 0 <= i < 25.

op2[i] - op2[i - 1] = ca[i] - cb[i]

For operation 3, if we pick 'a' + i as the breakpoint, we need to sum all ca[j] and cb[j] where j != i.

So op3[i] = SUM(ca) + SUM(cb) - ca[i] - cb[i]

// OJ: https://leetcode.com/problems/change-minimum-characters-to-satisfy-one-of-three-conditions/
// Author: github.com/lzl124631x
// Time: O(A + B)
// Space: O(1)
class Solution {
public:
    int minCharacters(string a, string b) {
        array<int, 26> ca = {}, cb = {};
        for (char c : a) ca[c - 'a']++;
        for (char c : b) cb[c - 'a']++;
        int M = a.size(), N = b.size(), op1 = M, op2 = N, ans = INT_MAX;
        for (int i = 0; i < 26; ++i) {
            op1 += cb[i] - ca[i];
            op2 += ca[i] - cb[i];
            if (i < 25) ans = min({ ans, op1, op2 });
            ans = min(ans, M + N - ca[i] - cb[i]);
        }
        return ans;
    }
};