zoukankan      html  css  js  c++  java
  • 单词拆分

    这是leetcode上的一道题

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

    说明:

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


    示例 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

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

    刚开始的时候,我的思路是这样的:如果原字符串s能被拆分成wordDict里的单词,那么wordDict里的单词肯定就是原字符串s的子串。用KMP算法,将wordDict里面的单词和原字符串匹配,如果所有单词都不能匹配,则表示原字符串不能被拆分成wordDict里的单词,返回false;如果可以找到一个单词,是字符串s的子串,那么将s去掉这个子串,继续验证去掉这个子串的s能不能被wordDict里的单词匹配。当最后s被拆分为一个空字符串后,说明这个单词是可以被拆分的。

    代码如下:

     1 class Solution {
     2     public boolean wordBreak(String s, List<String> wordDict) {
     3        while(!s.equals("")){
     4             boolean flag = false;
     5             for(String word : wordDict){
     6                 int i = KMP(s,word);
     7                 int j = 0;
     8                 if(i != -1){
     9                     flag = true;
    10                     j = i + word.length() - 1;
    11                     s = s.substring(0,i)+s.substring(j+1,s.length());
    12                     break;
    13                 }
    14             }
    15             if(!flag)
    16                 return false;
    17         }
    18         return true;
    19     }
    20 
    21     /*
    22      * KMP算法的实现
    23    */
    24     public int KMP(String str,String patten){
    25         char[] s = str.toCharArray();
    26         char[] ps = patten.toCharArray();
    27         int i = 0;
    28         int j = 0;
    29         int[] next =  getNext(patten);
    30         while(i < s.length && j < ps.length){
    31             if(j == -1 || s[i] == ps[j]){
    32                 i++;
    33                 j++;
    34             }else{
    35                 j = next[j];
    36             }
    37         }
    38         if( j == ps.length)
    39             return i-j;
    40         else
    41             return -1;
    42     }
    43     /*
    44      * 获取next[]数组(KMP算法里很关键的一部分
    45     */
    46     public int[] getNext(String patten){
    47         char[] p = patten.toCharArray();
    48         int[] next = new int[patten.length()];
    49         next[0] = -1;
    50         int k = -1;
    51         for(int i = 1; i < p.length-1; i++){
    52             if(k == -1 || p[i] == p[k]) {
    53                 next[++i] = ++k;
    54             }else
    55                 k = next[k];
    56         }
    57         return next;
    58     }
    59 }

    示例中的三个都通过了验证,但是这个解法是错误的。以以下这个例子为例

    输入:"cars"
             ["car","ca","rs"]
    
    输出:false
    
    预期:true

    为什么会出现这个错误呢?这是因为在代码中,我是用forEach遍历wordDict中的每个单词,由于wordDict中的"car"被遍历到,"car"又是"cars"的子串,"cars"就被拆分成"car"和"s"的组合,但是wordDict中没有"s",因此程序判定"cars"不能由wordDict中的单词组成,返回false。但实际上,"cars"可以由"ca"和"rs"组成,程序没有考虑到这个,因此出错。也就是说,以上的程序没有考虑到一个字符串可能有多种组合。

    介绍下官方题解中的使用宽度优先搜索来解这道题。

    官方题解的这个方法和我的方法的区别在于,它在搜索到"cars"不能由"car"和"s"组成后,并没有结束程序,而是继续搜索wordDict中是否还有其它组合。

    官方题解的代码如下:

     1     public boolean wordBreak(String s, List<String> wordDict) {
     2         Set<String> wordDictSet=new HashSet(wordDict);
     3         Queue<Integer> queue = new LinkedList<>();
     4         int[] visited = new int[s.length()];
     5         queue.add(0);
     6         while (!queue.isEmpty()) {
     7             int start = queue.remove();
     8             if (visited[start] == 0) {
     9                 for (int end = start + 1; end <= s.length(); end++) {
    10                     if (wordDictSet.contains(s.substring(start, end))) {
    11                         queue.add(end);
    12                         if (end == s.length()) {
    13                             return true;
    14                         }
    15                     }
    16                 }
    17                 visited[start] = 1;
    18             }
    19         }
    20         return false;
    21     }
    22 
    23 作者:LeetCode
    24 链接:https://leetcode-cn.com/problems/word-break/solution/dan-ci-chai-fen-by-leetcode/
    25 来源:力扣(LeetCode)
    26 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    官方的这个代码有个优化的空间,就是将visited的类型由int改为boolean,这样可以省部分空间。

  • 相关阅读:
    maven mirror
    cas sso单点登录系列8_抛弃Https让Cas以Http协议提供单点登录服务
    cas sso单点登录系列7_ 单点登录cas常见问题系列汇总
    cas sso单点登录系列6_cas单点登录防止登出退出后刷新后退ticket失效报500错
    cas sso单点登录系列5_cas单点登录增加验证码功能完整步骤
    cas sso单点登录系列4_cas-server登录页面自定义修改过程(jsp页面修改)
    cas sso单点登录系列3_cas-server端配置认证方式实践(数据源+自定义java类认证)
    cas sso单点登录系列2:cas客户端和cas服务端交互原理动画图解,cas协议终极分析
    cas sso单点登录系列1_cas-client Filter源码解码(转)
    Mysql事务机制
  • 原文地址:https://www.cnblogs.com/Chsy/p/11751125.html
Copyright © 2011-2022 走看看