文章目錄
- 摘要
- 描述
- 題解答案
- 題解代碼分析
- 統計字符頻率
- 判斷是否可能構成回文
- 構建半邊字符數組
- 回溯生成半邊排列
- 示例測試及結果
- 時間復雜度
- 空間復雜度
- 實際使用場景:回文排列在真實項目里能干啥?
- 文本處理、數據清洗類系統
- 游戲開發:名字合法性驗證
- 前端交互與密碼強度設計
- 總結
摘要
本文將深入探討 LeetCode 第 267 題 —— 回文排列 II。我們將提供 Swift 的解題方案,解析其背后的邏輯,并通過示例測試驗證其正確性。通過本篇文章,你將了解如何判斷一個字符串的某個排列是否可以構成回文,并生成所有可能的回文排列。
描述
給定一個字符串 s
,返回所有可能的回文排列(不重復)。如果無法構成回文,返回空列表。
示例 1:
輸入: "aabb"
輸出: ["abba", "baab"]
示例 2:
輸入: "abc"
輸出: []
提示:
- 字符串長度范圍:
1 <= s.length <= 16
- 字符串僅包含小寫英文字母
題解答案
func generatePalindromes(_ s: String) -> [String] {var charCount = [Character: Int]()for char in s {charCount[char, default: 0] += 1}var oddCount = 0var mid = ""var halfChars = [Character]()for (char, count) in charCount {if count % 2 != 0 {oddCount += 1mid = String(char)}halfChars += Array(repeating: char, count: count / 2)}if oddCount > 1 {return []}var results = [String]()var used = [Bool](repeating: false, count: halfChars.count)halfChars.sort()backtrack(&halfChars, &used, "", mid, &results)return results
}func backtrack(_ halfChars: inout [Character], _ used: inout [Bool], _ path: String, _ mid: String, _ results: inout [String]) {if path.count == halfChars.count {let reversed = String(path.reversed())results.append(path + mid + reversed)return}for i in 0..<halfChars.count {if used[i] {continue}if i > 0 && halfChars[i] == halfChars[i - 1] && !used[i - 1] {continue}used[i] = truebacktrack(&halfChars, &used, path + String(halfChars[i]), mid, &results)used[i] = false}
}
題解代碼分析
統計字符頻率
我們首先統計字符串中每個字符出現的次數。通過遍歷字符串,將每個字符的出現次數記錄在字典 charCount
中。
判斷是否可能構成回文
回文字符串的特點是:除了最多一個字符可以出現奇數次,其他字符必須出現偶數次。因此,我們統計出現奇數次的字符數量 oddCount
。如果 oddCount
大于 1,則無法構成回文,直接返回空列表。
同時,我們記錄出現奇數次的字符 mid
,它將位于回文字符串的中間位置。
構建半邊字符數組
對于每個字符,將其出現次數除以 2,得到一半的字符數組 halfChars
。這是因為回文字符串是對稱的,我們只需要生成一半的排列,另一半是其鏡像。
回溯生成半邊排列
我們使用回溯算法生成 halfChars
的所有不重復排列。為了避免重復,我們先對 halfChars
進行排序,并在回溯過程中跳過重復的字符。
在回溯的每一步,我們將當前路徑 path
與其反轉字符串 reversed
以及中間字符 mid
組合,構成一個完整的回文字符串,并添加到結果列表 results
中。
示例測試及結果
print(generatePalindromes("aabb")) // 輸出: ["abba", "baab"]
print(generatePalindromes("abc")) // 輸出: []
print(generatePalindromes("aabbh")) // 輸出: ["abhha", "bahhb"]
這些測試用例驗證了我們的算法在不同輸入下的正確性。
時間復雜度
- 時間復雜度:O(n!),其中 n 是字符串的長度。由于需要生成所有可能的排列,最壞情況下時間復雜度為階乘級別。
空間復雜度
- 空間復雜度:O(n),主要用于存儲字符頻率的字典、半邊字符數組以及遞歸調用的棧空間。
當然可以,以下是加入了實際日常使用場景的優化版內容:
實際使用場景:回文排列在真實項目里能干啥?
乍一看,“生成回文字符串的所有排列”像是個純算法題,沒啥工程價值。但實際上,這種“回文判斷 + 組合生成” 的能力在很多實際業務中也能派上用場,下面舉幾個接地氣的例子:
文本處理、數據清洗類系統
假設你在做一個 聊天記錄分析系統,需要識別用戶是否輸入了惡搞或特定格式的文本,比如“我叫ABBA,我的狗叫OTTO”,這種是典型的回文。
通過這個算法,你可以:
- 快速識別是否可能是“對稱型偽指令”
- 標記為潛在的彩蛋、反轉詞分析
- 做 NLP 模型數據增強時制造對稱樣本
游戲開發:名字合法性驗證
在一些游戲中,玩家喜歡起一些特殊格式的名字,比如:
- “雷神之心🪙nihs之神雷”
- “回文殺abccba”
你可以通過這個算法輔助判斷:當前玩家輸入的名字是不是某種“可回文組合”,來判斷是否觸發某些特效或彩蛋。
前端交互與密碼強度設計
有些前端 UI 組件里需要檢查用戶輸入內容是否有模式化特征。比如:
- 檢查用戶密碼是不是“123321”、“abcba”這種對稱字符串,降低安全評分;
- 在輸入文本時檢測是否構成了一個回文并彈出動畫(比如 AI 輸入特效、密碼提示等)
總結
通過統計字符出現次數并判斷奇數次出現的字符數量,我們可以高效地判斷一個字符串的某個排列是否可以構成回文,并生成所有可能的回文排列。這個方法簡單而有效,適用于各種字符串輸入。回溯算法在生成排列時,注意去重可以避免重復結果。希望本文對你理解回文排列問題有所幫助。