题目描述
思路解析动画文字版
记住「先数次数,再按 order 成串输出,最后补 order 外字符」,下面每帧都在套它。
第一段:从左到右扫 s,每遇到一个字符,就在「字符 → 出现次数」表里给它加一。
扫到第 0 个,是字符 'a'(绿色是它之前出现过的位置)。给它的出现次数加一。
字符 'a' 的出现次数更新到 1(高亮行)。继续往后扫。
扫到第 1 个,是字符 'b'(绿色是它之前出现过的位置)。给它的出现次数加一。
字符 'b' 的出现次数更新到 1(高亮行)。继续往后扫。
扫到第 2 个,是字符 'a'(绿色是它之前出现过的位置)。给它的出现次数加一。
字符 'a' 的出现次数更新到 2(高亮行)。继续往后扫。
扫到第 3 个,是字符 'c'(绿色是它之前出现过的位置)。给它的出现次数加一。
字符 'c' 的出现次数更新到 1(高亮行)。继续往后扫。
扫到第 4 个,是字符 'b'(绿色是它之前出现过的位置)。给它的出现次数加一。
字符 'b' 的出现次数更新到 2(高亮行)。继续往后扫。
扫到第 5 个,是字符 'd'(绿色是它之前出现过的位置)。给它的出现次数加一。
字符 'd' 的出现次数更新到 1(高亮行)。继续往后扫。
第一段扫完。各字符出现次数是 'a'→2,'b'→2,'c'→1,'d'→1。接下来第二段:按 order="cab" 的顺序把字符成串输出。
第二段:沿着 order="cab" 从左到右走。每个字符在表里有几个,就连续输出几个,然后把它的次数清零。
order 走到 'c',计数表里有 1 个 'c'(绿色是它在 s 中的位置)。一次性输出 1 个 'c',输出串变成 "c"。
把 'c' 的次数清零(高亮行已归 0,灰色表示这些位置已消化)。order 里没有重复字符,'c' 不会再被处理。
order 走到 'a',计数表里有 2 个 'a'(绿色是它在 s 中的位置)。一次性输出 2 个 'a',输出串变成 "caa"。
把 'a' 的次数清零(高亮行已归 0,灰色表示这些位置已消化)。order 里没有重复字符,'a' 不会再被处理。
order 走到 'b',计数表里有 2 个 'b'(绿色是它在 s 中的位置)。一次性输出 2 个 'b',输出串变成 "caabb"。
把 'b' 的次数清零(高亮行已归 0,灰色表示这些位置已消化)。order 里没有重复字符,'b' 不会再被处理。
order="cab" 全部走完,输出串是 "caabb"。但表里 'd' 的次数还没清零,因为它不在 order 里。第三步:再扫一遍 s,把这些剩下的字符补到末尾。
扫到 s[5]='d',它不在 order 里、表里还剩 1 个(红色是它的位置)。直接把 1 个 'd' 补到输出串末尾 → "caabbd",再清零。
表里所有次数都清零了,说明 s 的每个字符都进了输出串。最终重排结果 = "caabbd"。order 里的 'c'、'a'、'b' 按优先级在前,'d' 在最后。
边界先想清:全不在 order、已有序、order 极短都要对。
面试重点:小字符集 → 计数代替排序。
参考代码
class Solution: def customSortString(self, order: str, s: str) -> str: cnt = {ch: 0 for ch in set(s)} for ch in s: cnt[ch] = cnt.get(ch, 0) + 1 ans = [] for ch in order: ans.append(ch * cnt.get(ch, 0)) cnt[ch] = 0 for ch in s: if cnt.get(ch, 0): ans.append(ch * cnt[ch]) cnt[ch] = 0 return ''.join(ans)复杂度
- 时间:O(n + |order|),n 是 s 长度,扫 s 计数 + 扫 order 输出 + 扫 s 补尾
- 空间:O(1),计数表最多 26 个小写字母,常数级
易错点
面试追问把动画讲成自己的话
追问如果改用自定义比较器排序会怎样?
追问这题考的核心是什么?
这道题到这就讲完了。动画和文字是同一套思路——别光看,关掉页面自己默写一遍。然后顺着主线继续:
子域名访问计数
LeetCode 811 · 中等 · 沿着 哈希套路 继续往下推进
把这道题真正学会,再走
图解算法年卡 ¥99 /年
- ✓本题每步动画的吴师兄语音讲解(全站陆续覆盖)
- ✓小欧带 8 步通关训练——追问到不看答案也能写对、能 30 秒讲给面试官听
- ✓学习报告,记录每道题的掌握程度
76k+ GitHub Star · 吴师兄开源图解算法,几十万开发者在看的算法讲解
想成体系刷透这类套路?去图解算法专题