前言
近日面试,有这样的一些智力题。
1 硬币摆放问题
一个圆桌和若干硬币,你和另外一个人轮流放,一次放一个,放最后一个硬币的人赢。请设计策略,可以保证你一定赢。
在面试官的提示下,我最后的方案是:我先放,放在圆桌中心(记为O)。接下来,他放一个硬币(记为A),我放一个硬币(记为B)。使AOB三点在一条直线上,并且A到O距离(记为AO)=BO。
2 扑克牌问题
15张扑克牌,你和另外一个人轮流拿牌,一次拿2张或3张,请设计策略,可以确保你能拿最后一张牌。
这个有点类似海盗分金问题,我的思路是,倒着推,我拿最后一张,就可以推出来他最后拿哪些牌。这样,我们两个人每次拿牌个数的可能性可以构成一个二叉树,最后…,如果这样构思,就走进死胡同了。
因为事先听说过海盗分金问题,做过硬币摆放问题。我们就可以知道,对方每次拿多少张牌,还剩多少张牌,我们并不确定。但我们可以放大范围,将不确定的因素确定化,于是策略是:对方先拿,对方拿两张,我便拿三张。对方拿三张,我便拿两张,即每回我们两个人共拿5张。因为15是5的倍数,而我总是拿5的后半部分,即可确保最后一张由我来拿。
这样的题目并不难,但之所以单列出来,因为这样的题目跟我们平时解题的思路不同,即每一步不是确定的,而是前后有依赖关系。
而这对我也是有很大的启发意义的,因为我这个人是一个容易想的多的人,总是想确定每一步该怎么走,最后达到一个确定的结果(跟这个问题是多么的像)。但实际生活中,更多的还是靠随机应变,确定的结果只要阶段性的即可。有人说,不要做理想的俘虏,我说,不要做计划和设想的俘虏。
3 字母排列问题
一共四个字母,
第1个:AAAA
第2个:AAAB
...
最后一个:ZZZZ
那么,给一个随机数N(作为序号),请问其对应的排列是什么?
办法当然有很多,不过,从朋友那里看到一个非常精巧的办法,假设“AAAA”=0001,将其作为一个26进制数,
第N个排列 = 26进制的0001 + 十进制的 N
最后,将得到的26进制数翻译成字母即可。
4 一个循环实现九九乘法表
1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
看起来多么像{11,21,22,31}这些数字的十位数和个位数相乘啊
public class Test {
public static void main(String[] args) {
int curS = 1;
for(int i=11;i<100;i++){
int g = getG(i);
int s = getS(i);
// 十位数换了,就换行
if(s > curS){
curS = s;
System.out.println();
}
// 如果个位数为0或者个位数已经超过了十位数,就转到下一个十位
if(g == 0 || g > s){
i = (curS + 1) * 10;
}else{
System.out.print(s + "x" + g + "=" + (g * s) + " ");
}
}
}
public static int getS(int i){
return i/10;
}
public static int getG(int i){
return i%10;
}
}
求二进制数中1的个数
这种方法速度比较快,其运算次数与输入n的大小无关,只与n中1的个数有关。如果n的二进制表示中有k个1,那么这个方法只需要循环k次即可。其原理是不断清除n的二进制表示中最右边的1,同时累加计数器,直至n为0,代码如下
int BitCount2(unsigned int n){
unsigned int c =0 ;
for (c =0; n; ++c)
{
n &= (n -1) ; // 清除最低位的1
}
return c ;
}
关键是代码中对for循环的使用,一下子少写好几行代码,真的有点“代码之美”的意思。