Problem
There are n bulbs that are initially off.
- You first turn on all the bulbs.
- Then, you turn off every second bulb.
- On the third round, you toggle every third bulb (turning on if it’s off or turning off if it’s on).
- For the ith round, you toggle every i bulb.
- For the nth round, you only toggle the last bulb.
- Find how many bulbs are on after n rounds.
Example
Given n = 3.
At first, the three bulbs are [off, off, off].
After first round, the three bulbs are [on, on, on].
After second round, the three bulbs are [on, off, on].
After third round, the three bulbs are [on, off, off].
So you should return 1, because there is only one bulb is on.
Algorithm
整理一下题意:给定n个关闭的灯泡,进行一下过程:
首先点亮所有灯泡。然后每隔2个灯泡熄灭一个灯泡。第三轮,每隔三个灯泡改变一个灯泡的状态。在第i轮,每隔i个灯泡改变一个灯泡的状态。第n轮,每隔n个灯泡改变一个灯泡的状态。
试问第n轮后有多少只灯泡处于点亮状态。
一开始的思路是尝试找到一种循环,使得循环的每轮模拟一次改变灯泡状态的过程。最后在循环结束后再统计亮灯的数量。但是实际实现时发现比较繁复,于是尝试从数学的角度思考。
对于每个灯泡,可以视为一个数。这个灯泡在第i轮需要改变状态,说明这个数恰好是i的整数倍。
进一步思考可以发现,每当找到一个数的整数倍,总会找到对称的一个整数倍,例如 1*2,就肯定会有一个 2*1。也就是某个灯泡如果在某一轮被选中改变状态,那么根据对称性一定在另一轮它也被改变了状态。那么灯泡被改变状态的次数是偶数倍,即相当于与初始状态保持一致。唯一的例外出现在平方数上,例如 4 = 2*2,只有一次整数倍。
对于所有数来说,如果有偶数次整数倍,最终的灯泡都会还原为 off;只有奇数次整数倍,最终的灯泡都会 on。而奇数次整数倍的数都是平方数。
也就是说,最终亮的灯泡数目由小于其的最大平方数决定。如果n个灯泡,小于n的最大平方数是s,那么剩余s开平方个灯泡。
代码很简洁,如下。
class Solution {
public:
int bulbSwitch(int n) {
return (int)sqrt(n);
}
};