返回
LeetCode 139:单词拆分:巧解难题,逐层递进
见解分享
2024-01-24 20:09:28
前言
在 LeetCode 的浩瀚题海中,“单词拆分”无疑是一道备受青睐的经典题目,它考察了算法、数据结构和字符串处理等多方面的综合能力。这道题目不仅能检验你的编程功底,还能拓展你的算法思维,为解决更复杂的编程问题奠定坚实的基础。
本文将带领你踏上征服 LeetCode 139 的征程,我们将逐层递进,层层剖析题目的内涵,并为你提供巧妙的解法,让你对这道题目有深入的理解和熟练的掌握。
问题
给你一个字符串 s 和一个单词字典 wordDict,判定 s 是否可以被切割成一个或多个字典中的单词。你可以假设字典中没有重复的单词。
示例:
输入:s = "leetcode", wordDict = ["leet", "code"]
输出:true
解释:s 可以拆分成 "leet" 和 "code"。
输入:s = "applepenapple", wordDict = ["apple", "pen"]
输出:true
解释:s 可以拆分成 "apple"、"pen" 和 "apple"。
输入:s = "catsanddog", wordDict = ["cats", "dog", "sand", "and"]
输出:false
解释:s 无法拆分成字典中的单词。
解题思路
解决这道题目的关键在于理解它的本质:将一个字符串拆分成一系列子串,判断每个子串是否在给定的单词字典中。根据此思路,我们可以采用自顶向下的递归回溯算法,具体步骤如下:
- 递归基: 当字符串 s 为空时,表示拆分成功,返回 true。
- 枚举单词长度: 从长度为 1 开始,逐一增加单词长度,直到达到字符串 s 的长度。
- 子串匹配: 对于每个单词长度,从字符串 s 的开头开始,截取长度为该长度的子串。判断该子串是否在单词字典中,如果是,则继续递归处理剩余字符串。
- 回溯: 如果某一分支的递归处理失败,则回溯到上一个分支,继续尝试其他可能的拆分方式。
- 记录结果: 为避免重复计算,可以使用哈希表记录已经拆分成功的子字符串。
代码实现(Python)
def wordBreak(s, wordDict):
"""
:type s: str
:type wordDict: List[str]
:rtype: bool
"""
# 存储已经拆分成功的子字符串
memo = {}
def dfs(start):
# 非递归出口
if start == len(s):
return True
# 已经计算过的子串
if start in memo:
return memo[start]
# 枚举单词长度
for end in range(start + 1, len(s) + 1):
# 截取子串
substring = s[start:end]
# 判断子串是否在字典中
if substring in wordDict:
# 递归处理剩余字符串
if dfs(end):
memo[start] = True
return True
# 所有情况都失败
memo[start] = False
return False
return dfs(0)
时间复杂度
最坏情况下,每个子串都需要尝试所有可能的拆分方式,因此时间复杂度为 O(2^n),其中 n 为字符串 s 的长度。
空间复杂度
最坏情况下,每个子串都需要存储在哈希表中,因此空间复杂度为 O(n),其中 n 为字符串 s 的长度。
总结
恭喜你攻克了 LeetCode 139 题!通过本文的深入讲解和巧妙的解法,相信你对单词拆分问题的理解又上了一个台阶。
解决算法问题时,逐层递进的思维方式至关重要。将复杂问题分解成一个个小问题,再逐步解决,往往能事半功倍。此外,掌握高效的数据结构和算法也是提升编码能力的关键。
希望本文能助你提升算法思维,攻克更多编程难题!