leetcode(139). Word Break

problem

Given a non-empty string s and a dictionary wordDict containing a list
of non-empty words, determine if s can be segmented into a
space-separated sequence of one or more dictionary words. You may
assume the dictionary does not contain duplicate words.

For example, given s = “leetcode”, dict = [“leet”, “code”].

Return true because “leetcode” can be segmented as “leet code”.

solution

一开始我用的是类似于分治算法,先用wordDict中的word在字符串前面去匹配,如果匹配成功则将剩下的继续递归,但是这里面要考虑所有的情况,也就是对一个字符串找出所有前面匹配的情况,然后对这些可能的情况汇总,有一个成功即可。

def OR(ans):
    if len(ans) == 0:
        return False
    elif len(ans) == 1:
        return ans[0]
    else:
        return ans[0] or OR(ans[1:])
class Solution(object):
    def wordBreak(self, s, wordDict):
        """
        :type s: str
        :type wordDict: List[str]
        :rtype: bool
        """
        if s == "":
            return True
        ans = []

        for word in wordDict:
            if s[:len(word)] == word:
                ans.append(self.wordBreak(s[len(word):], wordDict))

        return OR(ans)

改进

上面的解法类似于爬楼梯问题中的递归解法,即反过来思考,但是对这样的问题反过来思考会出现重复的子问题,如果能将子问题记录下来就会提升很多效率,所以我们正向思考,使用动态规划解法,f(i)定义为前i个字符能否分成合法的word,这样的解法时间复杂度为 O(n)

这个问题不能长word优先或短word优先,反例:

  1. s=’leetcode’, wordDict = [‘lee’, ‘code’, ‘leet’]
  2. s=’leetcode’, wordDict = [‘leetc’, ‘code’, ‘leet’]
#超过了90%
class Solution(object):
    def wordBreak(self, s, wordDict):

        n = len(s)
        ans = [False]*(n+1)
        ans[-1] = True
        wordDict = set(wordDict)
        for i in range(n):
            for j in range(i+1):
                if s[j:i+1] in wordDict and ans[j-1]:
                    ans[i] = True
                    break

        print(ans)            
        return ans[n-1]

改进2

我们在内层循环时可以不遍历整个nums[:i],只遍历wordDict中的最长的长度。
超过了97%的提交。

class Solution(object):
    def wordBreak(self, s, wordDict):
        n = len(s)
        #python2中max没有default
        max_len = max([len(string) for string in wordDict] or [0])

        can_break = [False for _ in xrange(n + 1)]
        can_break[0] = True
        for i in xrange(1, n + 1):
            for l in xrange(1, min(i, max_len) + 1):
                if can_break[i-l] and s[i-l:i] in wordDict:
                    can_break[i] = True
                    break

        return can_break[-1]

变形

一块长度为n的木棍能否由长度为[i1, i2, … , ik]的短木棍拼成,短木棍数量不限。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值