单词拆分

问题描述:

给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。

拆分时可以重复使用字典中的单词。
       可以假设字典中没有重复的单词。
示例 1:

输入: s = "leetcode", wordDict = ["leet", "code"]
输出: true
解释: 返回 true 因为 "leetcode" 可以被拆分成 "leet code"。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/word-break
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解法一:递归

问题可以转化为以当前结点为开头的序列能否由字典表示,以0位置开头即为所求。遍历过程为,若从开头到当前的结点的子串在字典中,之后只需判断从当前结点后面开头的序列能否由字典表示;若可以 则以开头位置的字符串全部能由字典表示。实现代码如下:

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        return process(s, 0, new HashSet<>(wordDict));
    }

    public boolean process(String s, int start, Set<String> set){
        if(start == s.length()){
            return true;
        }
        for(int i = start + 1; i <= s.length(); i++){
            if(set.contains(s.substring(start, i)) && process(s, i, set)){
                return true;
            }
        }
        return false;
    }
}

解法二:带有记忆的递归

发现解法一中进行了大量的重复计算,因此很容易想到使用一个记忆存储计算结果。之后先进行判断,若存在则直接读取,不存在就进行同解法一那样计算。实现代码如下:

class Solution {
    public boolean wordBreak(String s, List<String> wordDict) {
        Boolean[] memo = new Boolean[s.length()]; // memo[i] 为以i开始能否拆成字典
        return process(s, 0, new HashSet<>(wordDict), memo);
    }

    public boolean process(String s, int start, Set<String> set, Boolean[] memo){
        if(start == s.length()){
            return true;
        }
        if(memo[start] != null){
            return memo[start];
        }
        for(int i = start + 1; i <= s.length(); i++){
            if(set.contains(s.substring(start, i)) && process(s, i, set, memo)){
                memo[start] = true;
                return true;
            }
        }
        memo[start] = false;
        return false;
    }
}

解法三:动态规划

dp算法的一般优化顺序为递归 => 递归+记忆集  => 动态规划

我们发现前面的结点求解只依赖后续结点的信息,可以从后往前依次计算结点的后缀能否由字典组成。此外由于我们只关心能由字典组成的后缀,可以使用list代替dp数组,list中只存储为true的下标。实现代码如下:

    public boolean wordBreak(String s, List<String> wordDict) {
        List<Integer> list = new ArrayList<>(); // 以list[i]作为开头可以由字典表示
        list.add(s.length());
        Set<String> set = new HashSet<>(wordDict);
        for(int i = s.length() - 1; i >= 0; i--){
            for(int end : list){
                if(set.contains(s.substring(i, end))){
                    list.add(i);
                    break;
                }
            }
        }
        // System.out.println(list);
        if(list.isEmpty() || list.get(list.size() - 1) != 0){
            return false;
        }
        return true;
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值