You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

238 lines
5.8 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class07;
import java.util.HashSet;
public class Code05_WorldBreak {
/*
*
* 假设所有字符都是小写字母. 大字符串是str. arr是去重的单词表, 每个单词都不是空字符串且可以使用任意次.
* 使用arr中的单词有多少种拼接str的方式. 返回方法数.
*
*/
public static int ways(String str, String[] arr) {
HashSet<String> set = new HashSet<>();
for (String candidate : arr) {
set.add(candidate);
}
return process(str, 0, set);
}
// 所有的可分解字符串都已经放在了set中
// str[i....] 能够被set中的贴纸分解的话返回分解的方法数
public static int process(String str, int i, HashSet<String> set) {
if (i == str.length()) { // 没字符串需要分解了!
return 1;
}
// i....还有字符串需要分解
int ways = 0;
// [i ... end] 前缀串 每一个前缀串
for (int end = i; end < str.length(); end++) {
String pre = str.substring(i, end + 1);// [)
if (set.contains(pre)) {
ways += process(str, end + 1, set);
}
}
return ways;
}
public static int ways1(String str, String[] arr) {
if (str == null || str.length() == 0 || arr == null || arr.length == 0) {
return 0;
}
HashSet<String> map = new HashSet<>();
for (String s : arr) {
map.add(s);
}
return f(str, map, 0);
}
public static int f(String str, HashSet<String> map, int index) {
if (index == str.length()) {
return 1;
}
int ways = 0;
for (int end = index; end < str.length(); end++) {
if (map.contains(str.substring(index, end + 1))) {
ways += f(str, map, end + 1);
}
}
return ways;
}
public static int ways2(String str, String[] arr) {
if (str == null || str.length() == 0 || arr == null || arr.length == 0) {
return 0;
}
HashSet<String> map = new HashSet<>();
for (String s : arr) {
map.add(s);
}
int N = str.length();
int[] dp = new int[N + 1];
dp[N] = 1;
for (int i = N - 1; i >= 0; i--) {
for (int end = i; end < N; end++) {
if (map.contains(str.substring(i, end + 1))) {
dp[i] += dp[end + 1];
}
}
}
return dp[0];
}
public static class Node {
public boolean end;
public Node[] nexts;
public Node() {
end = false;
nexts = new Node[26];
}
}
public static int ways3(String str, String[] arr) {
if (str == null || str.length() == 0 || arr == null || arr.length == 0) {
return 0;
}
Node root = new Node();
for (String s : arr) {
char[] chs = s.toCharArray();
Node node = root;
int index = 0;
for (int i = 0; i < chs.length; i++) {
index = chs[i] - 'a';
if (node.nexts[index] == null) {
node.nexts[index] = new Node();
}
node = node.nexts[index];
}
node.end = true;
}
return g(str.toCharArray(), root, 0);
}
// str[i...] 被分解的方法数,返回
public static int g(char[] str, Node root, int i) {
if (i == str.length) {
return 1;
}
int ways = 0;
Node cur = root;
// i...end
for (int end = i; end < str.length; end++) {
int path = str[end] - 'a';
if (cur.nexts[path] == null) {
break;
}
cur = cur.nexts[path];
if (cur.end) { // i...end
ways += g(str, root, end + 1);
}
}
return ways;
}
public static int ways4(String s, String[] arr) {
if (s == null || s.length() == 0 || arr == null || arr.length == 0) {
return 0;
}
Node root = new Node();
for (String str : arr) {
char[] chs = str.toCharArray();
Node node = root;
int index = 0;
for (int i = 0; i < chs.length; i++) {
index = chs[i] - 'a';
if (node.nexts[index] == null) {
node.nexts[index] = new Node();
}
node = node.nexts[index];
}
node.end = true;
}
char[] str = s.toCharArray();
int N = str.length;
int[] dp = new int[N + 1];
dp[N] = 1;
for (int i = N - 1; i >= 0; i--) {
Node cur = root;
for (int end = i; end < N; end++) {
int path = str[end] - 'a';
if (cur.nexts[path] == null) {
break;
}
cur = cur.nexts[path];
if (cur.end) {
dp[i] += dp[end + 1];
}
}
}
return dp[0];
}
// 以下的逻辑都是为了测试
public static class RandomSample {
public String str;
public String[] arr;
public RandomSample(String s, String[] a) {
str = s;
arr = a;
}
}
// 随机样本产生器
public static RandomSample generateRandomSample(char[] candidates, int num, int len, int joint) {
String[] seeds = randomSeeds(candidates, num, len);
HashSet<String> set = new HashSet<>();
for (String str : seeds) {
set.add(str);
}
String[] arr = new String[set.size()];
int index = 0;
for (String str : set) {
arr[index++] = str;
}
StringBuilder all = new StringBuilder();
for (int i = 0; i < joint; i++) {
all.append(arr[(int) (Math.random() * arr.length)]);
}
return new RandomSample(all.toString(), arr);
}
public static String[] randomSeeds(char[] candidates, int num, int len) {
String[] arr = new String[(int) (Math.random() * num) + 1];
for (int i = 0; i < arr.length; i++) {
char[] str = new char[(int) (Math.random() * len) + 1];
for (int j = 0; j < str.length; j++) {
str[j] = candidates[(int) (Math.random() * candidates.length)];
}
arr[i] = String.valueOf(str);
}
return arr;
}
public static void main(String[] args) {
char[] candidates = { 'a', 'b' };
int num = 20;
int len = 4;
int joint = 5;
int testTimes = 30000;
boolean testResult = true;
for (int i = 0; i < testTimes; i++) {
RandomSample sample = generateRandomSample(candidates, num, len, joint);
int ans1 = ways1(sample.str, sample.arr);
int ans2 = ways2(sample.str, sample.arr);
int ans3 = ways3(sample.str, sample.arr);
int ans4 = ways4(sample.str, sample.arr);
if (ans1 != ans2 || ans3 != ans4 || ans2 != ans4) {
testResult = false;
}
}
System.out.println(testTimes + "次随机测试是否通过:" + testResult);
}
}