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

    LeetCode链接:https://leetcode-cn.com/problems/word-break/

    题目:

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

      注:

        1、拆分时可以重复使用字典中的单词;

        2、可以假设字典中没有重复的单词;

      

      我的想法是使用回溯法,逐个查找s中可以在字典wordDict中匹配的单词

     1 import java.util.*;
     2 
     3 public class Solution {
     4     private List<String> wordDict;
     5     
     6     public boolean wordBreak(String s, List<String> wordDict) {
     7         this.wordDict = wordDict;
     8         return find(s, 0);
     9     }
    10     
    11     public boolean find(String s, int i)
    12     {
    13         if(i == s.length())
    14         {
    15             return true;
    16         }
    17         
    18         for(int j = i; j < s.length(); j++)  // 步骤2,如果步骤1中的后续匹配失败,则回退并将指针j后移,查找字典中是否包含其它子串
    19         {
    20             if(wordDict.contains(s.substring(i, j+1)))  
    21             {
    22                 if(find(s, j+1))     //步骤1,查找到在字典中的单词时,就继续进行后续匹配
    23                 {
    24                     return true;
    25                 }
    26             }
    27         }
    28         return false;
    29     }
    30 }

      上述算法的时间复杂度,在最好的情况下时间复杂度为O(n),即只需遍历一次字符串,但在最坏的情况下时间复杂度为O(n^n)。在leetcode的36个测试用例里通过了29个测试用例,提示说在某些测试用例上超时,如:s="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",wordDict=["a","aa","aaa","aaaa","aaaaa","aaaaaa","aaaaaaa","aaaaaaaa","aaaaaaaaa","aaaaaaaaaa"],在这个测试用例上,上述算法会存在大量的重复比较开销,有什么方法能避免重复比较呢?

      通过使用一个数组跟踪子串的匹配状态来避免重复比较,官方提供的三个时间复杂度为O(n^2),空间复杂度为O(n)的方法,看这里

     1 import java.util.*;
     2 
     3 public class Solution {
     4     private List<String> wordDict;
     5     
     6     private int[] memory;  //memory数组记录子串的匹配状态
     7     
     8     public boolean wordBreak(String s, List<String> wordDict) {
     9         this.wordDict = wordDict;
    10         this.memory = new int[s.length()];
    11         return find(s, 0);
    12     }
    13     
    14     public boolean find(String s, int i)
    15     {                                  
    16         if(i == s.length())
    17         {
    18             return true;
    19         }
    20         if(memory[i] == 1)   //memory[i]==1时,表明以i为起始的子串无法匹配
    21         {
    22             return false;
    23         }
    24         for(int j = i; j < s.length(); j++) 
    25         {
    26             if(wordDict.contains(s.substring(i, j+1)) && find(s, j+1))  
    27             {
    28                 return true;
    29             }
    30         }
    31         memory[i] = 1;
    32         return false;
    33     }
    34 }

    方法二:
     1 import java.util.*;
     2 
     3 public class Solution {    
     4     public boolean wordBreak(String s, List<String> wordDict) {
     5         int[] visited = new int[s.length()];
     6         Queue<Integer> queue = new LinkedList<>();
     7         queue.add(0);
     8         while(!queue.isEmpty()) {
     9             int start = queue.remove();
    10             if(visited[start] == 0) {  
    11                 for(int j = start+1; j <= s.length(); j++) {
    12                     if(wordDict.contains(s.substring(start, j))) {
    13                         queue.add(j);  //表明[0, j)已经在字典中找到匹配,下一次从j位置开始寻找
    14                         if(j == s.length()) {  //如果s已经全部匹配完毕,则返回true
    15                             return true;
    16                         }
    17                     }
    18                 }
    19                 visited[start] = 1;  //visited[start]==1,表示子串s.substring(start, s.length())在字典中没有找到匹配
    20             }
    21         }
    22         return false;
    23     }
    24 }

    方法三:动态规划

     1 import java.util.*;
     2 
     3 public class Solution {    
     4     public boolean wordBreak(String s, List<String> wordDict) {
     5         boolean[] dp = new boolean[s.length() + 1];   //dp[i]表示子串s.substring(0, i)已在字典中找到匹配
     6         dp[0] = true;
     7         for(int i = 1; i <= s.length(); i++) {
     8             for(int j = 0; j < i; j++) {
     9                 if(dp[j] && wordDict.contains(s.substring(j, i))) {  //如果dp[j]==false,说明s.substring(0,j)在字典中没有匹配的字符串,则就没有必要测试后续子串s.substring(j, i)
    10                     dp[i] = true;                                    //因为必须前面的匹配好了,才有进行后续匹配的必要
    11                     break;
    12                 }
    13             }
    14         }
    15         return dp[s.length()];  //如果dp[s.length()]==true,表明sub.substring(0, s.length())已经全部在字典中找到匹配
    16     }
    17 }
  • 相关阅读:
    css3——box-sizing属性
    HTML5存储--离线存储
    微信公众号爆出前端安全漏洞
    Js获取宽高度的归纳集锦总结
    Yii 2 修改 URL 模式为 PATH 模式,并隐藏index.php
    SQL 查询优化 索引优化
    linux提示语言包
    安装linux工作环境
    linux常用命令
    PHP解决抢购、秒杀、抢楼、抽奖等阻塞式高并发库存防控超量的思路方法
  • 原文地址:https://www.cnblogs.com/OoycyoO/p/11730181.html
Copyright © 2011-2022 走看看