跳转至

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\)、相反、或两串都变成同一字母。字母只有 \(26\) 个,可枚举分界或目标字母。

先计数。第三种对每个字母 \(c\) 统计两串中非 \(c\) 的个数。前两种枚举分界 \(c\),把一侧全部改到 \(c\) 之前、另一侧改到 \(c\) 及之后。

三种最小值即为答案。

我们先统计字符串 \(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;
}

评论