有些算法题目,只要掌握了思路就可以用很短的代码来实现它。比如下面这几道题目:
二的幂
问题
判断一个数字是否是2的n次方
解答
遇到2的幂次方,要建立位移操作的思想,如果n是二的幂,即最高位为1其他位置为0,那么n-1就是最高位为0,其余位置为1,那么n&(n-1)就是0
1boolean isPowerOfTow(int n){
2 return (n>0)%%(n&(n-1))==0;
3}
三的幂
问题
判断一个数字是否为3的n次方
解答
int类型中不溢出情况下3的最高次方即为1162261467,那么只要这个数去约n为0,那么说明n的约数只有三,即为3的n次方.
同样的做法也可以适用于5的幂,7的幂,X的幂(X是一个素数)之类的题目。
1boolean isPowerOfThree(int n){
2 return (n>0)&&(116261467%n)==0;
3}
二进制1的个数
问题
给定一个数字n,求n转换为二进制表示中1的个数
解答
JDK大法好,直接使用自带的方法:
- bitCount:返回二进制中1的个数
- lowestOneBit:返回二进制表示中最低位1的位置
- highestOneBit:返回二进制表示中最高位1的位置
- numberOfLeadingZeros:返回二进制表示中高位0的数目
- numberOfTrailingZeros:返回二进制表示中低位0的数目
1 int bitCount(int num) {
2 return Integer.bitCount(num);
3 }
或者也可以不使用jdk类库的解法
1int bitOfOne(int num) {
2 return num == 0 ? 0 : 1 + bitOfOne(num & (num - 1));
3 }
阶乘后的零
问题
给定一个数字n,求n!位数中的0的个数。
解答
这种问题我们要分析0的产生原因,因为10=52,对于一个n!的数字而言,末尾为0的数字即n!的约数中包含的52的次数,因为2的次数是足够的,也就是说这道题等价于求n!中约数5的个数(注意诸如25这种数字,约数中包括了2个5)。
1int zeroAtTheEndCount(int num) {
2 return num / 5 + zeroAtTheEndCount(num / 5);
3 }
熄灭的灯
问题
有x个灯,一个开关控制一个灯,按下开关会使灯熄灭或者打开,现在灯都是熄灭的状态,我们进行n次操作,每次操作都把编号为i的倍数的开关全部按下,即
- 将编号为1的倍数的开关全部按下
- 将编号为2的倍数的开关全部按下
- …
- 将编号为x的倍数的开关全部按下
已知灯的总数为x,求最后灯亮起来状态的数量
解答
首先任意取灯的编号n,会有几次操作会影响这个灯的状态呢?答案是n的所有约数的个数次。
好比说编号为12的灯,12的约数有1,2,3,4,6,12。也就是说编号为12的灯的状态会被切换6次,分别在第1,2,3,4,6,12次切换开关的时候。
那么从下面2种情况考虑:
- 假设n是一个非完全平方的数:因为为一个非平方的数的约数个数为偶数个,也就是说会切换偶数次状态,也就是说状态不会变。
- 假设n是一个完全平方数:完全平方数的约数是奇数个,其状态会发生改变。
那么按照题目的要求,一开始全是熄灭状态的,求亮起来状态的灯数目,就是说求会发生变化的编号的数目,也就是相当于求1~x之间完全平方数的个数。
1int lightCount(int num) {
2 return (int) Math.sqrt(num);
3 }
奇怪的数
问题
给定一个非空数组,其中除了一个元素只出现一次外,其他元素都出现了两次,求这个只出现一次的元素
解答
这里的一个关键运算符是^ 异或运算符,主要是利用到了异或运算a^b满足的如下规律:
- a^b=b^a 交换律
- a^b^c=a^(b^c)结合律
- a^a=0,同时0^0=0
- 0^a=a
1int loseNumber(int[] num) {
2 return Arrays.stream(num).reduce(0, (n1, n2) -> n1 ^ n2);
3 }
约瑟夫环问题
问题
编号为1-n的n个战士围成一圈,从编号1的战士开始依次报数,数到m的战士会淘汰,以后的战士再重新报数,直到剩下一个士兵,求这个士兵的编号