Bulb Switcher

1. 解析

 题目大意,给定n栈灯,初始状态为off(关),第i次将序号为i的倍数的灯的状态反转(即若当前为off则置为on,当前为on置为off),求解经过n次后,状态为on的灯的数量

2. 分析

很容易想到的解法就是,利用二层循环,第一层的 表示当前的次数,第二层 代表 i 的倍数,每一次循环,将序号为 i*j 的灯状态反转即可,最后统计当前状态为on的灯的数量.这种方法的时间复杂度为O(n^2),会提示时间超时.

例如:5个灯泡的情况,'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    √   

仔细分析,我们就会发现,最终保持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);
    }
};

[1]https://www.cnblogs.com/grandyang/p/5100098.html

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值