题目描述:
初始时有 n
个灯泡关闭。 第 1
轮,你打开所有的灯泡。 第 2
轮,每两个灯泡你关闭一次。 第 3
轮,每三个灯泡切换一次开关(如果关闭则开启,如果开启则关闭)。第 i
轮,每 i
个灯泡切换一次开关。 对于第 n
轮,你只切换最后一个灯泡的开关。 找出 n
轮后有多少个亮着的灯泡。
示例:
输入: 3
输出: 1
解释:
初始时, 灯泡状态 [关闭, 关闭, 关闭].
第一轮后, 灯泡状态 [开启, 开启, 开启].
第二轮后, 灯泡状态 [开启, 关闭, 开启].
第三轮后, 灯泡状态 [开启, 关闭, 关闭].
你应该返回 1,因为只有一个灯泡还亮着。
思路:
这题一开始就是想找规律来着,但是想半天也没想出来,就先用模拟做了一下。
Method 1:
简单模拟,直接做n轮开关切换,最后统计亮的灯泡数;
Method 2:
用模拟提交后显示击败百分之二十多的用户,感觉事情并没有那么简单,毕竟归为中等题;然后用模拟的结果测试了100
、1000
、10000
、100000
,结果得到10
、31
、100
,316
,发现有点意思,难不成结果是 n 的算数平方根?一提交果然Accept
,击败100%
的用户。
既然知道了结论,那么现在推起来就很顺利了。我们容易想到,对于第 i
个灯泡,它的状态被改变的次数应该是 i
的因子数次,那么如果对于一个数 i
,如果它的因子数是偶数,那么第 i
个灯泡的状态将被改变偶数次,也就是跟初始状态一样,而初始状态为熄灭,所以第 i
个灯泡:若 i
的因子数为奇数,则其最终亮着;若 i
的因子数为偶数,则其最终熄灭。
那么问题来了,什么样的数的因子数是偶数呢?我们知道,普通的数的因子是成对存在的,6 = 1 * 6 = 2 * 3
,8 = 1 * 8 = 2 * 4
,所以这种数的因子数肯定为偶数,而完全平方数的平方根因子是单独的,4 = 1 * 4 = 2 * 2
,那么其因子数为奇数。既然如此,结论就显而易见了,其实就是计算n
以内的完全平方数个数。
代码:
Method 1:
class Solution {
public int bulbSwitch(int n) {
boolean[] light = new boolean[n + 1];
for (int i = 1; i <= n; i++) {
onOrOff(light, i);
}
int count = 0;
for (int i = 0; i < light.length; i++) {
if (light[i]) {
count++;
}
}
return count;
}
public void onOrOff(boolean[] arr, int tag) {
for (int i = tag; i < arr.length; i += tag) {
arr[i] = !arr[i];
}
}
}
Method 2:
class Solution {
public int bulbSwitch(int n) {
return (int) Math.sqrt(n);
}
}