A/B/C/D/E五个人互相传球,由A开始第一次传球,经5次传球后传回到A的手上,其中A与B不会相互传球,C只会传给D,E不会传给C,共有多少种传法?
思路:
设接球人的序列为:AXXXXA,其中中间4位是未知的.
根据条件列出不合法的情况,及对应正则:
相邻两个相同的(自己不能传给自己):(.)\1+
A后是B或B后是A的:AB|BA
C后不是D的:C[^D]
E后是C的:EC
拼接起来就是:(.)\1+|AB|BA|C[^D]|EC
先不考虑条件找出所有可能,再把每种可能使用以上规则过滤一遍,得到的就是需求的
实现:
public static void main(String[] args) {
char[] cs = "ABCDE".toCharArray();
//不合法字串正则
Pattern pattern = Pattern.compile("(.)\\1+|AB|BA|C[^D]|EC");
//由A发球,经过5次传球又回到A受理,所以中间有4个人接球,求出所有可能
String[] result = samplingWithReplacement(cs, 4);
List<String> list = new ArrayList<>();
for (String s : result) {
//过滤掉不合法的
if (!pattern.matcher("A" + s + "A").find()) {
list.add("A" + s + "A");
}
}
System.out.println(list);
System.out.println(list.size());
}
/**
* 使用字符数组中的字符,组成长度为n的字符串,字符可以重复.
*
* @param chars
* @param n
* @return 结果长度为chars.length^n
*/
public static String[] samplingWithReplacement(char[] chars, int n) {
String[] preResult;
if (n < 1)
throw new IllegalArgumentException("n不能小于1");
if (n == 1) {
preResult = new String[] { "" };
} else {
preResult = samplingWithReplacement(chars, n - 1);
}
String[] result = new String[preResult.length * chars.length];
int i = 0;
for (String preString : preResult) {
for (char c : chars) {
result[i] = preString + c;
i++;
}
}
return result;
}
结果:
[ACDADA, ACDAEA, ACDBDA, ACDBEA, ACDCDA, ACDEDA, ADACDA, ADADEA, ADAEDA, ADBCDA, ADBDEA, ADBEDA, ADCDEA, ADEADA, ADEAEA, ADEBDA, ADEBEA, ADEDEA, AEACDA, AEADEA, AEAEDA, AEBCDA, AEBDEA, AEBEDA, AEDADA, AEDAEA, AEDBDA, AEDBEA, AEDCDA, AEDEDA]
30