制造字母异位词的最小步骤数 II 图解题解
这道题到底在问什么
- 输入
- s="leetcode", t="coats"
- 输出
- 7
- 输入
- s="night", t="thing"
- 输出
- 0 (已经互为异位词)
最优解:一步一步想明白
- 3记牢这一句:扫 s 加一、扫 t 减一,最后把每个字母桶的绝对值加起来。桶里是正数代表 s 多、要补给 t,是负数代表 t 多、要补给 s,补齐都得花绝对值那么多步。下面从清空计数表开始一步步走。
- 4先建一张计数表。两个串合起来只用到 8 种字母,l e t c o d a s,给每种字母一个桶,格子里前面是字母、后面是它当前的计数,一开始全是 0。接下来先扫 s、再扫 t,让这些数字动起来。
- 5读到 s 的第 0 个字符是 l。找到它的桶,计数加 1,现在桶 l 里是 1。紫色高亮的就是刚刚更新的那个桶。
- 6读到 s 的第 1 个字符是 e。找到它的桶,计数加 1,现在桶 e 里是 1。紫色高亮的就是刚刚更新的那个桶。
- 7读到 s 的第 2 个字符是 e。找到它的桶,计数加 1,现在桶 e 里是 2。e 已经是第 2 次出现了,leetcode 里有 3 个 e,这个桶会一路涨到 3。
- 8读到 s 的第 3 个字符是 t。找到它的桶,计数加 1,现在桶 t 里是 1。紫色高亮的就是刚刚更新的那个桶。
- 9读到 s 的第 4 个字符是 c。找到它的桶,计数加 1,现在桶 c 里是 1。紫色高亮的就是刚刚更新的那个桶。
- 10读到 s 的第 5 个字符是 o。找到它的桶,计数加 1,现在桶 o 里是 1。紫色高亮的就是刚刚更新的那个桶。
- 11读到 s 的第 6 个字符是 d。找到它的桶,计数加 1,现在桶 d 里是 1。紫色高亮的就是刚刚更新的那个桶。
- 12读到 s 的第 7 个字符是 e。找到它的桶,计数加 1,现在桶 e 里是 3。e 已经是第 3 次出现了,leetcode 里有 3 个 e,这个桶会一路涨到 3。
- 13读到 t 的第 0 个字符是 c。给它的桶减 1,现在桶 c 里是 0。桶 c 里 s 和 t 各消掉一个,慢慢往配平的方向走。
- 14读到 t 的第 1 个字符是 o。给它的桶减 1,现在桶 o 里是 0。桶 o 里 s 和 t 各消掉一个,慢慢往配平的方向走。
- 15读到 t 的第 2 个字符是 a。给它的桶减 1,现在桶 a 里是 -1。注意它变成了负数,说明这个字母 t 比 s 多,记成红色,后面要把它补给 s。
- 16读到 t 的第 3 个字符是 t。给它的桶减 1,现在桶 t 里是 0。桶 t 里 s 和 t 各消掉一个,慢慢往配平的方向走。
- 17读到 t 的第 4 个字符是 s。给它的桶减 1,现在桶 s 里是 -1。注意它变成了负数,说明这个字母 t 比 s 多,记成红色,后面要把它补给 s。
- 18结算字母 l 这个桶,里面是 1。是正数 1,说明 s 多出 1 个 l,要补 1 个到 t,累计步数加到 1,标红。
- 19结算字母 e 这个桶,里面是 3。是正数 3,说明 s 多出 3 个 e,要补 3 个到 t,累计步数加到 4,标红。
- 20结算字母 t 这个桶,里面是 0。正好是 0,说明 s 和 t 里这个字母一样多,已经配平,标绿,不用补,累计步数还是 4。
- 21结算字母 c 这个桶,里面是 0。正好是 0,说明 s 和 t 里这个字母一样多,已经配平,标绿,不用补,累计步数还是 4。
- 22结算字母 o 这个桶,里面是 0。正好是 0,说明 s 和 t 里这个字母一样多,已经配平,标绿,不用补,累计步数还是 4。
- 23结算字母 d 这个桶,里面是 1。是正数 1,说明 s 多出 1 个 d,要补 1 个到 t,累计步数加到 5,标红。
- 24结算字母 a 这个桶,里面是 -1。是负数 -1,说明 t 多出 1 个 a,要补 1 个到 s,累计步数加到 6,标红。
- 25结算字母 s 这个桶,里面是 -1。是负数 -1,说明 t 多出 1 个 s,要补 1 个到 s,累计步数加到 7,标红。
- 26八个桶全部结算完。绿色的 t c o 三个字母 s 和 t 里一样多,不花步数;红色的 l 有 1 个多、e 有 3 个多、d 有 1 个多,这 5 个要补到 t,a 和 s 各差 1 个要补到 s。把红色桶的绝对值加起来,1 加 3 加 1 加 1 加 1 等于 7,这就是最少步骤数。
⚠️ 容易写错的地方
✗ 错:每扫一个字符就立刻取绝对值累加
✓ 对:先把 s 全加、t 全减,最后统一对各桶取绝对值求和
同一个字母在 s 和 t 里都会出现,中途取绝对值会把还没抵消完的量算重,答案偏大
✗ 错:以为要让 s 和 t 变成完全相同的字符串
✓ 对:只需每种字母个数相等即可,顺序无所谓
异位词只看每种字母的数量,不要求排列一致,按字母计数就够了
✗ 错:桶出现负数当成出错
✓ 对:负数代表这个字母 t 比 s 多,是正常情况
正数是 s 多要补给 t,负数是 t 多要补给 s,取绝对值后都算补齐的步数
✗ 错:想着通过删除字符来配平
✓ 对:题目只允许追加,永远是给少的一方补齐
不能删改,所以每种字母的差额只能靠往缺的那边追加来消除
完整代码(Python / C++ / Java)
Python
from __future__ import annotations
from typing import *
from collections import *
from functools import *
from itertools import *
from math import *
from heapq import *
from bisect import *
class Solution:
def minSteps(self, s: str, t: str) -> int:
cnt = Counter(s)
for c in t:
cnt[c] -= 1
return sum(abs(v) for v in cnt.values())C++
#include <algorithm>
#include <array>
#include <cctype>
#include <climits>
#include <cmath>
#include <deque>
#include <functional>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
using namespace std;
class Solution {
public:
int minSteps(string s, string t) {
vector<int> cnt(26);
for (char& c : s) ++cnt[c - 'a'];
for (char& c : t) --cnt[c - 'a'];
int ans = 0;
for (int& v : cnt) ans += abs(v);
return ans;
}
};Java
import java.util.*;
class Solution {
public int minSteps(String s, String t) {
int[] cnt = new int[26];
for (char c : s.toCharArray()) {
++cnt[c - 'a'];
}
for (char c : t.toCharArray()) {
--cnt[c - 'a'];
}
int ans = 0;
for (int v : cnt) {
ans += Math.abs(v);
}
return ans;
}
}复杂度
时间
O(n + m)
n 是 s 的长度、m 是 t 的长度。扫一遍 s 做加法、扫一遍 t 做减法,最后再扫固定的字母桶求和,桶只有 26 个是常数,所以整体随两个串的总长度线性增长
空间
O(1)
只用一张按字母计数的表。字母表固定 26 个,不随串长变化,是常数级空间;Python 的 Counter 最多也只存下 26 种小写字母,同样是常数
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 制造字母异位词的最小步骤数 II 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
这题的核心思路一句话怎么说?+
互为字母异位词等价于每种字母在两个串里的个数相等。用一张计数表,扫 s 给对应字母加 1、扫 t 给对应字母减 1,扫完后每个字母桶里就是 s 比 t 多出的净量,把所有桶的绝对值加起来就是要追加的最少步数。因为只能追加不能删,谁少了就补给谁。
如果改成可以删除字符,答案会变吗?+
不会变。无论是把 s 多的那部分删掉,还是把 t 缺的那部分补上,针对某个字母的差额,处理它的次数都等于这个差额的绝对值。所以只允许追加、或者允许删除,单看每个字母的最小操作数都是同一个绝对值,总和不变。
为什么时间是线性、空间是常数?+
扫 s 一遍、扫 t 一遍都是线性的,最后求和只需要过一遍固定的 26 个字母桶,是常数。空间上只维护这张 26 个桶的计数表,不随串的长度增长,所以是 O(1)。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄声线把 制造字母异位词的最小步骤数 II 一步步讲透(全站 0 节语音精讲,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。