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