單詞拆分

方法 1:暴力
算法
最簡單的實現方法是用遞歸和回溯。爲了找到解,咱們能夠檢查字典單詞中每個單詞的可能前綴,若是在字典中出現過,那麼去掉這個前綴後剩餘部分迴歸調用。同時,若是某次函數調用中發現整個字符串都已經被拆分且在字典中出現過了,函數就返回 true 。算法

public boolean wordBreak(String s, List<String> wordDict) { return word_Break(s, new HashSet(wordDict), 0); } public boolean word_Break(String s, Set<String> wordDict, int start) { if (start == s.length()) { return true; } for (int end = start + 1; end <= s.length(); end++) { if (wordDict.contains(s.substring(start, end)) && word_Break(s, wordDict, end)) { return true; } } return false; }

方法 2:記憶化回溯
算法數組

在先前的方法中,咱們看到許多函數調用都是冗餘的,也就是咱們會對相同的字符串調用屢次回溯函數。爲了不這種狀況,咱們可使用記憶化的方法,其中一個 memomemo 數組會被用來保存子問題的結果。每當訪問到已經訪問過的後綴串,直接用 memomemo 數組中的值返回而不須要繼續調用函數。函數

經過記憶化,許多冗餘的子問題能夠極大被優化,回溯樹獲得了剪枝,所以極大減少了時間複雜度。優化

public boolean wordBreak(String s, List<String> wordDict) { return word_Break(s, new HashSet(wordDict), 0, new Boolean[s.length()]); } public boolean word_Break(String s, Set<String> wordDict, int start, Boolean[] memo) { if (start == s.length()) { return true; } if (memo[start] != null) { return memo[start]; } for (int end = start + 1; end <= s.length(); end++) { if (wordDict.contains(s.substring(start, end)) && word_Break(s, wordDict, end, memo)) { return memo[start] = true; } } return memo[start] = false; }

方法 3:使用動態規劃

算法spa

這個方法的想法是對於給定的字符串(s)能夠被拆分紅子問題 s1 和 s2 。若是這些子問題均可以獨立地被拆分紅符合要求的子問題,那麼整個問題 s 也能夠知足。也就是,若是 "catsanddog" 能夠拆分紅兩個子字符串 "catsand" 和 "dog" 。子問題 "catsand" 能夠進一步拆分紅 "cats" 和 "and" ,這兩個獨立的部分都是字典的一部分,因此 "catsand" 知足題意條件,再往前, "catsand" 和 "}dog" 也分別知足條件,因此整個字符串 "catsanddog" 也知足條件。指針

如今,咱們考慮 dp 數組求解的過程。咱們使用 n+1大小數組的dp ,其中 n 是給定字符串的長度。咱們也使用 2 個下標指針 i 和 j ,其中 i 是當前字符串從頭開始的子字符串(s')的長度, j 是當前子字符串(s')的拆分位置,拆分紅 s'(0,j)和 s'(j+1,i)code

爲了求出 \text{dp}dp 數組,咱們初始化dp[0] 爲true ,這是由於空字符串老是字典的一部分。 dp 數組剩餘的元素都初始化爲 falseblog

咱們用下標 i 來考慮全部從當前字符串開始的可能的子字符串。對於每個子字符串,咱們經過下標 j 將它拆分紅 s1' 和 s2' (注意 i 如今指向 s2' 的結尾)。爲了將dp[i] 數組求出來,咱們依次檢查每一個 dp[j] 是否爲 true,也就是子字符串 s1' 是否知足題目要求。若是知足,咱們接下來檢查 s2' 是否在字典中。若是包含,咱們接下來檢查 s2' 是否在字典中,若是兩個字符串都知足要求,咱們讓 dp[i] 爲 true ,不然令其爲false遞歸

public boolean wordBreak(String s, List<String> wordDict) { Set<String> wordDictSet=new HashSet(wordDict); boolean[] dp = new boolean[s.length() + 1]; dp[0] = true; for (int i = 1; i <= s.length(); i++) { for (int j = 0; j < i; j++) { if (dp[j] && wordDictSet.contains(s.substring(j, i))) { dp[i] = true; break; } } } return dp[s.length()]; }
相關文章
相關標籤/搜索