Leetcode刷题笔记 139. 单词拆分

139. 单词拆分

知识点:字典树,字符串匹配,动态规划
时间:2020年11月1日
题目链接:https://leetcode-cn.com/problems/word-break

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

说明:

  1. 拆分时可以重复使用字典中的单词。
  2. 你可以假设字典中没有重复的单词。

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

示例 2:
输入: s = “applepenapple”, wordDict = [“apple”, “pen”]
输出: true
解释: 返回 true 因为 “applepenapple” 可以被拆分成 “apple pen apple”。
注意你可以重复使用字典中的单词。

示例 3
输入: s = “catsandog”, wordDict = [“cats”, “dog”, “sand”, “and”, “cat”]
输出: false

解法
用到了字典树(用来判断前缀、后缀,在这里比hash表速度更快):

  1. 如果头节点的next对应的字符未创建,创建空间,节点往下走
  2. 等到整个字符输入完成后,标记下已结束
    此题用来判断后缀,所以倒着入站,looked—>dekool
    root节点
    -> [d,0]->[e,0]->[k,0]->[e,0]->[d,1]
    -> [t,0]->[s,0]->[u,0]->[j,1]
    -> [e,0]->[k,0]->[i,0]->[l,1]
    -> [r,0]->[e,0]->[h,1]->[t,0]->[o,0]->[r,0]->[b,1]
    最后字典树就变了这样,其中红色节点代表字符结束
    在这里插入图片描述
  3. 动态规划,走到这个点看看能否用之前的加上这个字符拼成
举例:
 apple pen apple
 10000 100 10000 1

代码

#include <stdio.h>
#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;


/*

class Solution {
 public:
     bool wordBreak(string s, vector<string>& wordDict) {
         unordered_set<string> wordDictSet = unordered_set <string> ();
         for (string word: wordDict) {
            wordDictSet.insert(word);
         }
         vector<bool> dp = vector <bool> (s.size() + 1,false);
         dp[0] = true;
         for (int i = 1; i <= s.size(); ++i) {
             for (int j = 0; j < i; ++j) {
                 if (dp[j] && wordDictSet.find(s.substr(j, i - j)) != wordDictSet.end()) {
                     dp[i] = true;
                     break;
                 }
             }
         }
         return dp[s.size()];
     }
 };
 
*/
class Trie {
public:
    Trie* next[26] = {nullptr};
    bool isend;
    
    Trie(){
    	isend = false;
    }
    
    void insert(string s){
        Trie *tmp = this;
        for(int i = s.size()-1;i >= 0;i--){
            int idx = s[i] - 'a';
            if(tmp ->next [idx] == nullptr){
                tmp -> next[idx] = new Trie();
            }
            tmp = tmp -> next[idx];
        }
        tmp -> isend = true;
    }
};
class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        Trie* root = new Trie();
        int n = s.length();
        vector<int> dp(n+1,0);
        for(string s : wordDict)
            root->insert(s);
            
        dp[0] = true;
        for(int i = 1;i <= n;i++){
            Trie* tmp = root;
            for(int j = i-1;j >= 0;j--){
                int x = s[j] - 'a';
                if(tmp->next[x] == nullptr){
                	break;
                }
                else if (tmp->next[x]->isend == true && dp[j]){
                    dp[i] = true;
                    break;
                }
                tmp = tmp->next[x];
            }
        }
        return dp[n];
    }
};
int main()
{
    vector<string> d(10);
    d[0] = "aaaa";d[1]="aaa";
    string st = "aaaaaaa";
    Solution s ;
    cout<<s.wordBreak(st, d);
    return 0;
}

今天也是爱zz的一天哦!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值