回文十进制数
如果把某个数的各个数字按相反的顺序排列,得到的数和原来的数相同,则这个数就是“回文数”。譬如 123454321就是一个回文数。
问题
求用十进制、二进制、八进制表示都是回文数的所有数字中,大于十进制数 10 的最小值。
十进制数、二进制数和八进制数数示例
思路
因为是二进制的回文数,所以如果最低位是 0,那么相应的最高位也就是 0。但是,以 0 开头肯定是不恰当的,由此可知最低位置为 1。
如果用二进制表示时最低位为 1,那这个数一定是奇数,因此只考虑奇数的情况就可以。接下来可以简单地编写程序,从 10 的下一个数字 11 开始,按顺序搜索。比如用 Ruby 就可以通过下面的代码找到符合条件的数(代码清单 01.01)。
代码清单 01.01(q01_01.rb)
# 从 11 开始搜索
num = 11
while true
if num.to_s == num.to_s.reverse &&
num.to_s(8) == num.to_s(8).reverse &&
num.to_s(2) == num.to_s(2).reverse
puts num
break
end
# 只搜索奇数,每次加 2
num += 2
end
下面试着用 JavaScript 实现同样的逻辑。JavaScript 里没有内置把字符串逆序的标准函数,因此首先需要封装一个返回逆序字符串的方法,其他流程则和代码清单 01.01 中的一致。JavaScript 版本的实现如代码清单 01.02 所示。
代码清单 01.02(q01_02.js)
/* 为字符串类型添加返回逆序字符串的方法 */
String.prototype.reverse = function (){
return this.split("").reverse().join("");
}
/* 从 11 开始搜索 */
var num = 11;
while (true){
if ((num.toString() == num.toString().reverse()) &&
(num.toString(8) == num.toString(8).reverse()) &&
(num.toString(2) == num.toString(2).reverse())){
console.log(num);
break;
}
/* 只搜索奇数,每次加 2 */
num += 2;
}
Point
很多语言都提供了把整数转换成二进制数或者八进制数的方法法。表 2 汇总了代表性语言的相关函数或者方法,不过 C 语言并没有提供直接转换的接口
各编程语言中进制转换的接口
答案
- 二进制数是 1001001001
- 八进制数是 1111
数列的四则运算
大家小时候可能也玩过“组合车牌号里的 4 个数字最终得到 10”的游戏。
组合的方法是在各个数字之间插入四则运算的运算符组成算式,然后计算算式的结果(某些数位之间可以没有运算符,但最少要插入 1 个运算符)。
- 例)1234 → 1+ 2×3 - 4= 3
- 9876 → 9×87+ 6= 789
假设这里的条件是,组合算式的计算结果为“将原数字各个数位上的数逆序排列得到的数”,并且算式的运算按照四则运算的顺序进行(先乘除,后加减)。
那么位于 100~999,符合条件的有以下几种情况。
- 351 → 3×51= 153
- 621 → 6×21= 126
- 886 → 8×86= 688
问题
求位于 1000~9999,满足上述条件的数。
思路
解决这个问题时,“计算机的方法”会影响实现方法。如果要实现在的是计算器,那么通常会用到逆波兰表示法 A,而本题则是使用英语言语内置的功能来实现更为简单。
很多脚本语言都提供了类似 eval 这 羊 的 标 准 函 数。 譬 如 用JavaScript 实现时,可以用代码清单 02.01 解决问题。
var op = ["+", "-", "*", "/", ""];
for (i = 1000; i < 10000; i++){
var c = String(i);
for (j = 0; j < op.length; j++){
for (k = 0; k < op.length; k++){
for (l = 0; l < op.length; l++){
val = c.charAt(3) + op[j] + c.charAt(2) + op[k] +
c.charAt(1) + op[l] + c.charAt(0);
if (val.length > 4){ /* 一定要插入 1 个运算符 */
if (i == eval(val)){
console.log(val + " = " + i);
}
}
}
}
}
}
第 10 行中的 eval 就是本题的关键点,接下来只是选择和设置运算符了。虽然有比较深的循环嵌套,但只要确定了位数就没有问题。
逆波兰表示法(Reverse Polish notation,RPN)也称逆波兰记法,是由波兰数学家扬·武卡谢维奇与于 1920 年引入的数学表达式,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。——编者注
基于这样的考虑,如果把代码第 1 行的 op 变量设置成以下值,可以进一步提高程序执行效率。
var op = ["*", ""];
Point
如果用其他语言实现同样逻辑,需要对 0 进行特别处理。例如在Ruby 中,“以 0 开头的数”会被当作八进制数来处理,因此必须排除以0 开头的数。此外,也需要排除除数为 0 的情况。
答案
5931(5 * 9 * 31 = 1395)
最后
Ruby 为主要语言编写源代码,但也有像本题一样用JavaScript 实现的情况。凡用 JavaScript 实现时,结果都用 console.log 来输出,这个结果可以用浏览器来确认。用 Mozilla Firefox 浏览器打开加载了 JavaScript 源代码的 HTML 文件,然后打开“开发者”→“Web控制台”(如果用 Google Chrome 浏览器,则是打开“更多工具”→“开发者工具”),就可以确认代码的执行结果了。