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 }

 

 

posted @ 2019-10-24 08:39  Latuper  阅读(567)  评论(0编辑  收藏  举报