跳转至

1737. 满足三条件之一需改变的最少字符数

题目描述

给你两个字符串 ab ,二者均由小写字母组成。一步操作中,你可以将 ab 中的 任一字符 改变为 任一小写字母

操作的最终目标是满足下列三个条件 之一

  • a 中的 每个字母 在字母表中 严格小于 b 中的 每个字母
  • b 中的 每个字母 在字母表中 严格小于 a 中的 每个字母
  • ab 同一个 字母组成。

返回达成目标所需的 最少 操作数

 

示例 1:

输入:a = "aba", b = "caa"
输出:2
解释:满足每个条件的最佳方案分别是:
1) 将 b 变为 "ccc",2 次操作,满足 a 中的每个字母都小于 b 中的每个字母;
2) 将 a 变为 "bbb" 并将 b 变为 "aaa",3 次操作,满足 b 中的每个字母都小于 a 中的每个字母;
3) 将 a 变为 "aaa" 并将 b 变为 "aaa",2 次操作,满足 a 和 b 由同一个字母组成。
最佳的方案只需要 2 次操作(满足条件 1 或者条件 3)。

示例 2:

输入:a = "dabadd", b = "cda"
输出:3
解释:满足条件 1 的最佳方案是将 b 变为 "eee" 。

 

提示:

  • 1 <= a.length, b.length <= 105
  • ab 只由小写字母组成

解法

方法一:计数 + 枚举

我们先统计字符串 \(a\)\(b\) 中每个字母出现的次数,记为 \(cnt_1\)\(cnt_2\)

然后考虑条件 \(3\),即 \(a\)\(b\) 中的每个字母都相同。我们只需要枚举最终的字母 \(c\),然后统计 \(a\)\(b\) 中不是 \(c\) 的字母的个数,即为需要改变的字符个数。

然后考虑条件 \(1\)\(2\),即 \(a\) 中的每个字母都小于 \(b\) 中的每个字母,或者 \(b\) 中的每个字母都小于 \(a\) 中的每个字母。对于条件 \(1\),我们令字符串 \(a\) 所有字符都小于字符 \(c\),字符串 \(b\) 所有字符都不小于 \(c\),枚举 \(c\) 找出最小的答案即可。条件 \(2\) 同理。

最终的答案即为上述三种情况的最小值。

时间复杂度 \(O(m + n + C^2)\),其中 \(m\)\(n\) 分别为字符串 \(a\)\(b\) 的长度,而 \(C\) 为字符集大小。本题中 \(C = 26\)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
class Solution:
    def minCharacters(self, a: str, b: str) -> int:
        def f(cnt1, cnt2):
            for i in range(1, 26):
                t = sum(cnt1[i:]) + sum(cnt2[:i])
                nonlocal ans
                ans = min(ans, t)

        m, n = len(a), len(b)
        cnt1 = [0] * 26
        cnt2 = [0] * 26
        for c in a:
            cnt1[ord(c) - ord('a')] += 1
        for c in b:
            cnt2[ord(c) - ord('a')] += 1
        ans = m + n
        for c1, c2 in zip(cnt1, cnt2):
            ans = min(ans, m + n - c1 - c2)
        f(cnt1, cnt2)
        f(cnt2, cnt1)
        return ans
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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);
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
    int minCharacters(string a, string b) {
        int m = a.size(), n = b.size();
        vector<int> cnt1(26);
        vector<int> cnt2(26);
        for (char& c : a) ++cnt1[c - 'a'];
        for (char& c : b) ++cnt2[c - 'a'];
        int ans = m + n;
        for (int i = 0; i < 26; ++i) ans = min(ans, m + n - cnt1[i] - cnt2[i]);
        auto f = [&](vector<int>& cnt1, vector<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 = min(ans, t);
            }
        };
        f(cnt1, cnt2);
        f(cnt2, cnt1);
        return ans;
    }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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;
}

评论