题目: 天平称重
用天平称重时,我们希望用尽可能少的砝码组合称出尽可能多的重量。
如果只有5个砝码,重量分别是1,3,9,27,81
则它们可以组合称出1到121之间任意整数重量(砝码允许放在左右两个盘中)。
本题目要求编程实现:对用户给定的重量,给出砝码组合方案。
例如:
用户输入:
5
程序输出:
9-3-1
用户输入:
19
程序输出:
27-9+1
要求程序输出的组合总是大数在前小数在后。
可以假设用户的输入的数字符合范围1~121。
1. 递归解法
模拟几组称重数据, 设整数n的排列方式为f(n)
f(1) = 1
f(2) = 3 - 1 = 3 - f(1)
f(3) = 3
f(4) = 3 + f(1)
f(5) = 9 - 3 - 1 = 9 - f(5)
主要要发现 n 与{1,3,9,27,81}
的关系
代码:
// 将+,-号调换, 相当于式子 *-1, 顺序不能变
static String reve(String s) {
s = s.replace('-','#');
s = s.replace('+','-');
s = s.replace('#','+');
return "-" + s;
}
static String f(int n) {
int s = 1;
while (s < n) {
s *= 3;
}
if (n == s) return s + "";
else if (n <= s/2) {
return s/3 + "+" + f(n - s/3);
} else {
return s + reve(f(s - n));
}
}
注意的地方是, 需要变符号
2. 进制解法
进制解法相对来说更好理解一些
{1,3,9,27,81}
其实都是3的次方{3^0, 3^1, 3^2, 3^3, 3^4}
那我们就可以通过将一个数字转换成3进制来表示这个数字
例如28, 用3进制表示就是1001
, 因此等于 28 = 3^3 + 3^0 = 27 + 1
但要注意3进制里会存在2, 这时需要将2转换, 在使用短除法遇到余数为2的情况的时候, 可以将余数2转换为-1, 商+1
例如19, 原来用3进制表示是201
转换以后可以表示为1-101 = 3^3 - 3^2 + 3^0 = 27 - 9 + 1
代码:
static String f2(int n) {
int[] t = {1, 3, 9, 27, 81, 0};
int[] arr = new int[100];
int i = 0;
while(n != 0) {
arr[i] = n % 3;
n /= 3;
if (arr[i] == 2) {
arr[i] = -1;
n += 1;
}
i++;
}
String s = "";
for (int j = i; j >= 0; j--) {
int flag = arr[j];
if (t[j]*flag == 0) continue;
else if (t[j]*flag > 0 && s.length() > 0) {
s += "+";
}
s += (t[j]*flag);
}
return s;
}