【Leetcode刷题】单词拆分

139. 单词拆分

https://leetcode-cn.com/problems/word-break/

class Solution(object):
    def wordBreak(self, s, wordDict):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: bool
        """
        # dp[i]表示s[:i]能否被拆分
        # 如何计算dp[i]:枚举以s[i-1]结尾的字符串片段s[j:i]
        # dp[i] = dp[j] && s[j:i] in wordDict
        # 初始化dp[0]=True。最终返回dp[n]
        if not wordDict:
            return False
        n = len(s)
        dp = [False for _ in range(n+1)]
        dp[0] = True
        # set的搜索只需要O(1)的时间复杂度,而list需要O(n)
        word_set = set(wordDict)
        # 单词的最大长度
        max_len = max(len(word) for word in word_set)
        for i in range(1, n+1):
            # s[j:i]的长度应小于或等于单词的最大长度
            board = max(0, i - max_len)
            j = i - 1
            while j >= board:
                if dp[j] and (s[j:i] in word_set):
                    dp[i] = True
                    break
                j -= 1
        return dp[n]

时间复杂度:O(n^2)。需要枚举n个状态,每个状态需要枚举n个分割点 j,set的搜索需要O(1)的时间复杂度,因此总的时间复杂度为O(n^2)

空间复杂度:O(n)

140. 单词拆分 II

https://leetcode-cn.com/problems/word-break-ii/

class Solution(object):
    def wordBreak(self, s, wordDict):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: List[str]
        """
        if not wordDict:
            return []
        # dp[i]记录所有以s[i-1]结尾的单词起始位置
        # 如何计算dp[i]:枚举以s[i-1]结尾的字符串片段s[j:i]
        # if dp[j] && s[j:i] in wordDict, dp[i].append(j)
        # 然后从后往前深度优先遍历
        n = len(s)
        dp = [[] for _ in range(n + 1)]
        # dp[0]=True。考虑匹配到第一个单词s[0:i]时,dp[i+1]=[0]
        dp[0] = True
        # 单词的最大长度,往前找到这个长度还找不到就不需要再找下去了
        max_len = max(len(word) for word in wordDict)
        # set的搜索只需要O(1)的时间复杂度,而list需要O(n)
        word_set = set(wordDict)
        for i in range(1, n + 1):
            # 注意下界的取值,下界是取不到的,所以要-1
            for j in range(i - 1, max(0, i - max_len) - 1, -1):
                # 找到所有以s[i-1]结尾的单词起始位置
                if s[j:i] in word_set and dp[j]:
                    dp[i].append(j)

        words_list = []
        # 当前路径
        words = []

        def dfs(i):
            # 一条能够全部拆分的路径最终会取到dp[0]
            if i == 0:
                words_list.append(words[:])
                return
            for j in dp[i]:
                # 将单词取出
                words.append(s[j:i])
                dfs(j)
                # 回溯
                words.pop()

        dfs(n)
        result = []
        for words in words_list:
            result.append(" ".join(word for word in words[::-1]))
        return result

本题的时间与空间复杂度均为指数级别,较难进行具体的分析

posted @ 2020-11-02 15:11  luozx207  阅读(122)  评论(0编辑  收藏  举报