Hi 你们好,我是张小猪。欢迎来到『宝宝也能看懂』系列之 leetcode 周赛题解。git
这里是第 175 期的第 2 题,也是题目列表中的第 1347 题 -- 『制造字母异位词的最小步骤数』github
给你两个长度相等的字符串 s
和 t
。每个步骤中,你能够选择将 t
中的 任一字符 替换为 另外一个字符。shell
返回使 t
成为 s
的字母异位词的最小步骤数。segmentfault
字母异位词 指字母相同,但排列不一样的字符串。优化
示例 1:spa
输出:s = "bab", t = "aba" 输出:1 提示:用 'b' 替换 t 中的第一个 'a',t = "bba" 是 s 的一个字母异位词。
示例 2:code
输出:s = "leetcode", t = "practice" 输出:5 提示:用合适的字符替换 t 中的 'p', 'r', 'a', 'i' 和 'c',使 t 变成 s 的字母异位词。
示例 3:blog
输出:s = "anagram", t = "mangaar" 输出:0 提示:"anagram" 和 "mangaar" 自己就是一组字母异位词。
示例 4:leetcode
输出:s = "xxyyzz", t = "xxyyzz" 输出:0
示例 5:字符串
输出:s = "friend", t = "family" 输出:4
提示:
1 <= s.length <= 50000
s.length == t.length
s
和 t
只包含小写英文字母MEDIUM
题目的意思仍是很直白的,其中最关键的一个信息就是,须要让 t
成为 s
的字母异位词。那么什么是字母异位词呢?即两个字符串包含的字母的种类和数量都同样。至于字母之间的排列顺序,这里上面官方的中文题目描述实际上是有问题的,由于英文原文是 "with a different (or the same) ordering.",因此字母顺序实际上是能够不一样,也能够相同的。
既然没有了顺序的顾虑,那么咱们面临的问题就只剩一个啦 -- 保证两个字符串中字母的种类和数量都同样。那么说到这里,咱们第一件要作的事情其实已经很是明显了,就是对字符串进行字母频率统计。如何统计呢?相信看过周赛第一题的小伙伴能够轻松的想到,经过遍历字符串并结合字典计数,即可完成对于字符串中出现字母的种类和数量进行统计。
假设如今咱们已经有了两个字符串的字母统计结果,咱们应该如何找到最小的替换步数呢?这里咱们能够想象一下,对比这两个字符串的字母统计结果,其实只可能会出现两种状况:
t
中某个字母的数量比 s
中多。t
中某个字母的数量比 s
中少。因为咱们每一次替换字母是无任何要求的,因此咱们能够将任何一个 t
比 s
多的字母替换为一个 t
比 s
少的字母。而且,因为 t
和 s
这两个字符串的长度必定相等,因此咱们这里多出的数量和少的数量必定是相等的。也就是说,咱们最终要找的最少的替换步数,其实就是这个多出的数量或者少的数量。
基于上面分析的思路,咱们能够获得以下的流程:
t
字符串中比 s
多的数量。基于这个流程,咱们能够实现相似下面的代码:
const minSteps = (s, t) => { const BASE = 97; const count1 = new Int32Array(26); const count2 = new Int32Array(26); for (let i = 0; i < s.length; ++i) { ++count1[s.charCodeAt(i) - BASE]; } for (let i = 0; i < t.length; ++i) { ++count2[t.charCodeAt(i) - BASE]; } let step = 0; for (let i = 0; i < 26; ++i) { step += count1[i] > count2[i] ? count1[i] - count2[i] : 0; } return step; };
上面的代码里,咱们统计了两次计数结果,而且也遍历了两次字符串长度。那么咱们是否能够削减一半呢?
这时咱们注意一下最终咱们须要的是什么,会发现其实咱们要的只是二者的差值,而它们的数量到底是多少其实咱们是不关心的。基于这个想法,咱们能够尝试直接在一次遍历中计算差值,而不是统计总数量。
基于上面分析的思路,咱们能够获得以下的流程:
基于这个流程,咱们能够实现相似下面的代码:
const minSteps = (s, t) => { const BASE = 97; const count = new Int32Array(26); for (let i = 0; i < s.length; ++i) { ++count[s.charCodeAt(i) - BASE]; --count[t.charCodeAt(i) - BASE]; } let step = 0; for (let i = 0; i < 26; ++i) { count[i] > 0 && (step += count[i]); } return step; };
这道题内容很是直白,而核心的点就在于最终需求的要求。一旦咱们分析明白了这个需求,咱们也就能够很容易的基于此获得实现方案。
其实熟悉了的话,彻底能够直接写出上面优化版本的代码,小猪在比赛中也是直接提交的这个代码。不过为了展现这个优化的思路,小猪在这里仍是先给出了直接方案的代码。小猪是否是很贴心鸭,嘿嘿嘿~ 快夸夸小猪,嘤嘤嘤 >.<