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; };
這道題內容很是直白,而核心的點就在於最終需求的要求。一旦咱們分析明白了這個需求,咱們也就能夠很容易的基於此獲得實現方案。
其實熟悉了的話,徹底能夠直接寫出上面優化版本的代碼,小豬在比賽中也是直接提交的這個代碼。不過爲了展現這個優化的思路,小豬在這裏仍是先給出了直接方案的代碼。小豬是否是很貼心鴨,嘿嘿嘿~ 快誇誇小豬,嚶嚶嚶 >.<