1、题目描述
初始时有 n 个灯泡处于关闭状态。第一轮,你将会打开所有灯泡。接下来的第二轮,你将会每两个灯泡关闭一个。
第三轮,你每三个灯泡就切换一个灯泡的开关(即,打开变关闭,关闭变打开)。第 i 轮,你每 i 个灯泡就切换一个灯泡的开关。直到第 n 轮,你只需要切换最后一个灯泡的开关。
找出并返回 n 轮后有多少个亮着的灯泡。
2、算法分析
1、常规方法:
定义一个boolean的数组,true代表灯亮的,false表示熄灭。默认全是亮着的。
每间隔i个就切换开关。可以使用两个for循环控制。
最后统计数组中为true的个数。
但是最后有一个999999这个用例过不去。有点可惜。
2、比较吊的方法,就一行代码,数学推理。也好理解。
知识补充:什么是因子?
假如整数n除以m,结果是无余数的整数,那么我们称m就是n的因子。因子是整数中的概念。一个整数n的因子数为包含它自身的所有因子个数。例如,12的因子数为6(1,2,3,4,6,12)。
初始有n个灯泡关闭。第i轮的操作是每i个灯泡切换一次开关(开->闭,闭->开),即切换i的倍数位置的开关。
求n轮后亮着的灯泡?
(1)第i轮时,被切换的灯泡位置是i的倍数。
(2)由(1)得出,对于第p个灯泡来说,只有其第“因子”轮才会切换,若其有q个因子,则最终被切换q次。因为初始状态是关闭状态,那么因子数是奇数的灯泡最终是亮着的。
(3)只有平方数的因子个数不是成对出现,举例:4=1*4,2*2,其因子是1,2,4。
(4)那么题目最终转化为1~n里平方数的个数,进而转化为对n开平方根,向下取整即可。
3、代码实现
常规方法:
class Solution {
public int bulbSwitch(int n) {
if(n == 0){
return 0;
}
int resCount = 0;
boolean[] light = new boolean[n + 1];
Arrays.fill(light,true);
// 从第二个开始
for(int i = 2;i <= n;i++){
// 间隔着开关
for(int j = i;j <= n;j += i){
light[j] = !light[j];
}
}
// 计数
for(int i = 1;i <= n;i++){
if(light[i]){
resCount++;
}
}
return resCount;
}
}
数学推理:
import java.util.*;
class Solution {
public int bulbSwitch(int n) {
// 取平方根
return (int) Math.floor(Math.sqrt(n));
}
}