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,这样可以省部分空间。

  • 相关阅读:
    AUDIT审计的一些使用
    HOW TO PERFORM BLOCK MEDIA RECOVERY (BMR) WHEN BACKUPS ARE NOT TAKEN BY RMAN. (Doc ID 342972.1)
    使用BBED理解和修改Oracle数据块
    Using Class of Secure Transport (COST) to Restrict Instance Registration in Oracle RAC [ID 1340831.1]
    调试利器GDB概念
    第4章 思科IOS
    第3章 ip地址和子网划分
    第2章 TCPIP
    2020年阅读过的黑客资源推荐篇
    第1章 计算机网络
  • 原文地址:https://www.cnblogs.com/Chsy/p/11751125.html
Copyright © 2011-2022 走看看