import java.util.*; /** * NC182 单词拆分(二) * @author d3y1 */ public class Solution { private int len; private ArrayList<String> list = new ArrayList<>(); private HashSet<String> set = new HashSet<>(); /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param s string字符串 * @param dic string字符串一维数组 * @return string字符串一维数组 */ public String[] wordDiv (String s, String[] dic) { // return solution1(s, dic); return solution2(s, dic); // return solution3(s, dic); // return solution4(s, dic); } /** * 动态规划 * * dp[i]表示字符串s前i个字符组成的字符串能否拆分 * * dp[i] = dp[j] && check(s[j..i−1]) , 0<=j<i * check(s[j..i−1]) => map.getOrDefault(suffix, false) * 其中 check(s[j..i−1]) 表示子串s[j..i−1]是否出现在字典中 * * @param s * @param dic * @return */ private String[] solution1(String s, String[] dic){ int n = s.length(); int min = Integer.MAX_VALUE; int max = Integer.MIN_VALUE; int len; HashMap<String, Boolean> map = new HashMap<>(); for(String word: dic){ len = word.length(); min = Math.min(min, len); max = Math.max(max, len); map.put(word, true); } boolean[] dp = new boolean[n+1]; dp[0] = true; ArrayList<String>[] list = new ArrayList[n+1]; for(int i=1; i<=n; i++){ int gap; String suffix; for(int j=i-1; j>=0; j--){ gap = i-j; if(gap < min){ continue; } if(max < gap){ break; } suffix = s.substring(j, i); if(dp[j] && map.getOrDefault(suffix, false)){ dp[i] = true; if(list[i] == null){ list[i] = new ArrayList<String>(); } if(list[j]!=null && list[j].size() > 0){ for(String part: list[j]){ list[i].add(part + " " + suffix); } }else{ list[i].add(suffix); } } } } int size = 0; if(list[n] != null){ size = list[n].size(); } String[] result = new String[size]; for(int i=0; i<size; i++){ result[i] = list[n].get(i); } return result; } /** * 动态规划: 简化 * * dp[i]表示字符串s前i个字符组成的字符串的所有拆分方案 * * 判断是否可拆分 * dp[j]!=null && map.getOrDefault(suffix, false) , 0<=j<i * check(s[j..i−1]) => map.getOrDefault(suffix, false) * 其中 check(s[j..i−1]) 表示子串s[j..i−1]是否出现在字典中 * * @param s * @param dic * @return */ private String[] solution2(String s, String[] dic){ int n = s.length(); int min = Integer.MAX_VALUE; int max = Integer.MIN_VALUE; int len; HashMap<String, Boolean> map = new HashMap<>(); for(String word: dic){ len = word.length(); min = Math.min(min, len); max = Math.max(max, len); map.put(word, true); } ArrayList<String>[] dp = new ArrayList[n+1]; dp[0] = new ArrayList<>(); for(int i=1; i<=n; i++){ int gap; String suffix; for(int j=i-1; j>=0; j--){ gap = i-j; if(gap < min){ continue; } if(max < gap){ break; } suffix = s.substring(j, i); if(dp[j]!=null && map.getOrDefault(suffix, false)){ if(dp[i] == null){ dp[i] = new ArrayList<>(); } if(dp[j]!=null && dp[j].size() > 0){ for(String part: dp[j]){ dp[i].add(part + " " + suffix); } }else{ dp[i].add(suffix); } } } } int size = 0; if(dp[n] != null){ size = dp[n].size(); } String[] result = new String[size]; for(int i=0; i<size; i++){ result[i] = dp[n].get(i); } return result; } /** * dfs: 字典树Trie * @param s * @param dic * @return */ private String[] solution3(String s, String[] dic){ Trie root = new Trie(); for(String word: dic){ root.insert(word); } len = s.length(); for(int i=1; i<=len; i++){ dfs(s, root, 0, i, ""); } String[] result = new String[list.size()]; for(int i=0; i<list.size(); i++){ result[i] = list.get(i); } return result; } /** * 递归 * @param s * @param root * @param i * @param j * @param result */ private void dfs(String s, Trie root, int i, int j, String result){ String sub = s.substring(i, j); if(root.search(sub)){ if(j == len){ list.add(result+sub); }else{ String pre = s.substring(j, j+1); if(root.prefixNumber(pre) > 0){ for(int k=j+1; k<=len; k++){ dfs(s, root, j, k, result+sub+" "); } } } } } /** * 字典树Trie */ private class Trie { private Trie[] children; boolean isEnd; private int count; public Trie(){ children = new Trie[75]; isEnd = false; count = 0; } public void insert(String word){ Trie curr = this; int index; for(char ch: word.toCharArray()){ index = ch - '0'; if(curr.children[index] == null){ curr.children[index] = new Trie(); } curr = curr.children[index]; curr.count++; } curr.isEnd = true; } public void delete(String word){ Trie curr = this; int index; for(char ch: word.toCharArray()){ index = ch - '0'; if(curr.children[index] != null){ curr = curr.children[index]; curr.count--; } } if(curr.count == 0){ curr.isEnd = false; } } public boolean search(String word){ Trie curr = this; int index; for(char ch: word.toCharArray()){ index = ch - '0'; if(curr.children[index] == null){ return false; } curr = curr.children[index]; } if(!curr.isEnd){ return false; } return true; } public int prefixNumber(String pre){ Trie curr = this; int index; for(char ch: pre.toCharArray()){ index = ch - '0'; if(curr.children[index] == null){ return 0; } curr = curr.children[index]; } return curr.count; } } /** * dfs: HashSet * @param s * @param dic * @return */ private String[] solution4(String s, String[] dic){ len = s.length(); for(String word: dic){ set.add(word); } dfs(s, 0, ""); String[] result = new String[list.size()]; for(int i=0; i<list.size(); i++){ result[i] = list.get(i).trim(); } return result; } /** * 递归 * @param s * @param i * @param result */ private void dfs(String s, int i, String result){ if(i == len){ list.add(result); } String sub = ""; // for(int j=i; j<len; j++){ // sub += s.charAt(j); // if(set.contains(sub)){ // dfs(s, j+1, result+sub+" "); // } // } for(int j=i+1; j<=len; j++){ sub = s.substring(i, j); if(set.contains(sub)){ dfs(s, j, result+sub+" "); } } } }