用java編寫在1,2,…,9(順序不能變)數字之間插入+或-或什麼都不插入,使得計算結果總是100的程式,並輸出所有的可能性。例如:1 + 2 + 34 – 5 + 67 – 8 + 9 = 100
阿新 • • 發佈:2019-02-05
今天看到一個題目,編寫一個在1,2,…,9(順序不能變)數字之間插入+或-或什麼都不插入,使得計算結果總是100的程式,並輸出所有的可能性。例如:1 + 2 + 34 – 5 + 67 – 8 + 9 = 100。
剛開始看到題目的時候一籌莫展,但是題目下一條留言點撥了我:+、-和不插入可以對應2、1和0這三個數字,1到9之間有8個空位,所以有3的8次方種可能性,即6561種組合。8位3進位制數正好對應這些排列組合。
有了思路之後使用Java實現:
先寫一個進位制轉換的方法:
/**
* 實現將十進位制數num轉換成radix進位制數
*
* @param num
* 十進位制數
* @param radix
* 進位制
* @return 轉換後的數
*/
public static String radixConvert(int num, int radix) {
StringBuilder sb = new StringBuilder();
boolean flag = false; // 正負標記
if (num == 0) {
return "0";
} else if (num < 0) {
num = num * -1;
flag = true;
}
while (num > 0) {
int m = num % radix;
num = num / radix;
sb.append(m);
}
if (flag) {
sb.append("-");
}
// 倒敘輸出字串
return sb.reverse().toString();
}
使用javax.script包中的計算類,可以執行字串算術表示式得到計算結果
Map<Character, String> map = new HashMap<>();
map.put('0', "");
map.put('1', "-");
map.put('2', "+");
// javax.script包提供的運算類,可以計算字串算術表示式得到運算結果
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
String str = null;
StringBuilder expressions = null;
for (int i = 0; i < 6561; i++) {
// 將數字轉換為8位3進位制
str = "0000000" + radixConvert(i, 3);
str = str.substring(str.length() - 8);
// 算術表示式以1開頭
expressions = new StringBuilder("1");
for (int j = 0; j < 8; j++) {
expressions.append(map.get(str.charAt(j))).append(j + 2);
}
// 得到運算結果
int result = (int) engine.eval(expressions.toString());
if (result == 100) {
System.out.println(expressions.toString());
}
}
最後得到的結果是:
123-45-67+89
123-4-5-6-7+8-9
123+45-67+8-9
123+4-5+67-89
12-3-4+5-6+7+89
12+3-4+5+67+8+9
12+3+4+5-6-7+89
1+23-4+56+7+8+9
1+23-4+5+6+78-9
1+2+34-5+67-8+9
1+2+3-4+5+6+78+9
共11種。
這種實現方法思路簡單,程式碼少,缺點是計算速度比較慢。
慢的原因主要是ScriptEngine類運算算數表示式的效率比較低,鑑於我們這裡用到的算數表示式只有比較簡單的加減運算,我們可以自己寫一個簡單的加減算數表示式計算方法:
/**
* 運算簡單的加減算數表示式
*
* @param expressions
* 算數表示式
* @return
*/
public static int simpleEval(String expressions) {
int tempIndex = 0;
List<Integer> numberList = new ArrayList<>(); // 數字列表
List<Character> operatorList = new ArrayList<>(); // 運算子列表
for (int i = 0; i < expressions.length(); i++) {
if (expressions.charAt(i) == '+' || expressions.charAt(i) == '-') {
numberList.add(Integer.parseInt(expressions.substring(tempIndex, i)));
operatorList.add(expressions.charAt(i));
tempIndex = i + 1;
}
}
// 當表示式裡沒有運算子,即表示式為一個數字,直接輸出
if (operatorList.size() == 0) {
return Integer.parseInt(expressions);
}
// 把最後一個運算子後的數字加入數字列表
if (tempIndex < expressions.length()) {
numberList.add(Integer.parseInt(expressions.substring(tempIndex, expressions.length())));
}
// 計算結果
int result = numberList.get(0);
for (int i = 0; i < operatorList.size(); i++) {
if (operatorList.get(i) == '+') {
result = result + numberList.get(i + 1);
} else if (operatorList.get(i) == '-') {
result = result - numberList.get(i + 1);
}
}
return result;
}
使用這個方法替代ScriptEngine.eval可以大幅提高效率,下面貼出完整的程式碼:
public static void main(String[] args) {
Map<Character, String> map = new HashMap<>();
map.put('0', "");
map.put('1', "-");
map.put('2', "+");
String str = null;
StringBuilder expressions = null;
for (int i = 0; i < 6561; i++) {
// 將數字轉換為8位3進位制
str = "0000000" + radixConvert(i, 3);
str = str.substring(str.length() - 8);
// 算術表示式以1開頭
expressions = new StringBuilder("1");
for (int j = 0; j < 8; j++) {
expressions.append(map.get(str.charAt(j))).append(j + 2);
}
// 得到運算結果
int result = simpleEval(expressions.toString());
if (result == 100) {
System.out.println(expressions.toString());
}
}
}
/**
* 運算簡單的加減算數表示式
*
* @param expressions
* 算數表示式
* @return
*/
public static int simpleEval(String expressions) {
int tempIndex = 0;
List<Integer> numberList = new ArrayList<>(); // 數字列表
List<Character> operatorList = new ArrayList<>(); // 運算子列表
for (int i = 0; i < expressions.length(); i++) {
if (expressions.charAt(i) == '+' || expressions.charAt(i) == '-') {
numberList.add(Integer.parseInt(expressions.substring(tempIndex, i)));
operatorList.add(expressions.charAt(i));
tempIndex = i + 1;
}
}
// 當表示式裡沒有運算子,即表示式為一個數字,直接輸出
if (operatorList.size() == 0) {
return Integer.parseInt(expressions);
}
// 把最後一個運算子後的數字加入數字列表
if (tempIndex < expressions.length()) {
numberList.add(Integer.parseInt(expressions.substring(tempIndex, expressions.length())));
}
// 計算結果
int result = numberList.get(0);
for (int i = 0; i < operatorList.size(); i++) {
if (operatorList.get(i) == '+') {
result = result + numberList.get(i + 1);
} else if (operatorList.get(i) == '-') {
result = result - numberList.get(i + 1);
}
}
return result;
}
/**
* 實現將十進位制數num轉換成radix進位制數
*
* @param num
* 十進位制數
* @param radix
* 進位制
* @return 轉換後的數
*/
public static String radixConvert(int num, int radix) {
StringBuilder sb = new StringBuilder();
boolean flag = false; // 正負標記
if (num == 0) {
return "0";
} else if (num < 0) {
num = num * -1;
flag = true;
}
while (num > 0) {
int m = num % radix;
num = num / radix;
sb.append(m);
}
if (flag) {
sb.append("-");
}
// 倒敘輸出字串
return sb.reverse().toString();
}
比之前使用ScriptEngine.eval的效率提高了兩個數量級,幾十毫秒就執行完了