1. 解析
题目大意,给定n栈灯,初始状态为off(关),第i次将序号为i的倍数的灯的状态反转(即若当前为off则置为on,当前为on置为off),求解经过n次后,状态为on的灯的数量
2. 分析
很容易想到的解法就是,利用二层循环,第一层的 i 表示当前的次数,第二层 j 代表 i 的倍数,每一次循环,将序号为 i*j 的灯状态反转即可,最后统计当前状态为on的灯的数量.这种方法的时间复杂度为O(n^2),会提示时间超时.
例如:5个灯泡的情况,'X'表示灭,‘√’表示亮,如下所示:
初始状态: X X X X X
第一次: √ √ √ √ √
第二次: √ X √ X √
第三次: √ X X X √
第四次: √ X X √ √
第五次: √ X X √ X
class Solution {
public:
int bulbSwitch(int n) {
vector<bool> bulbs(n + 1, false); //初始状态
for (int i = 1; i <= n; ++i){
for (int j = 1; i * j <= n; ++j){
bulbs[i*j] = ! bulbs[i*j];
}
}
return count(bulbs.begin(), bulbs.end(), true);
}
};
3. 第二种解法
采用@Grandyang的思路,他虽然进行了详细的分析,但我觉得不是特别清楚,我参考了大量的博文,感觉大同小异。后来深入分析,恍然大悟~~~我讲解一下这种解法的思路
例如:4个灯泡的情况,'X'表示灭,‘√’表示亮,如下所示:
初始状态: X X X X
第一次: √ √ √ √
第二次: √ X √ X
第三次: √ X X X
第四次: √ X X √
仔细分析,我们就会发现,最终保持on状态的为第1个和第4个,第1盏灯是亮的,因为1的因子为[1, 1],第1次点亮后,就会往前移动,故第1盏是亮的,很好理解;第2盏灯,2的因子为[1, 2],即第1次点亮后,第2次重新熄灭,故恢复原状;第3盏灯,3的因子为[1, 3],即第1次点亮后,第3次重新熄灭,故恢复原状;第4盏灯,4的因子为[1, 4]、[2, 2],即第1次点亮后,在第4次重新熄灭,故恢复原状,虽然4可以分解成[2, 2],但每次点燃的顺序是会移动的,所以会改变最终第4盏灯的状态。即判定第n盏灯最终的状态,我们只需判断对该灯的操作次数时奇数还是偶数即可,若是奇数,则最终状态为on,若为偶数,不改变最初的状态。例如有100盏灯,我们判断第40盏灯最终的状态,40的因子为[1, 40], [2, 20], [4, 10], [5, 8],大家可以看到因子的个数是偶数个,即第1次改变最初状态,在第40次又恢复该状态,在第2次改变最初状态,在第20次又恢复最初状态,......,所以第40栈灯的最终状态和初态相同。我们要将每一盏灯单独分析,这样就很容易理解啦,不知道是不是讲清楚了~~~~
最终,我们可以得出结论,若灯的序号为完全平方数,则最终状态会改变初态,其他一律不改变初态。
class Solution {
public:
int bulbSwitch(int n){
return (int)sqrt(n);
}
};