灯泡开关

原题  leetcode 319题

初始时有 n 个灯泡处于关闭状态。第一轮,你将会打开所有灯泡。接下来的第二轮,你将会每两个灯泡关闭一个。

第三轮,你每三个灯泡就切换一个灯泡的开关(即,打开变关闭,关闭变打开)。第 i 轮,你每 i 个灯泡就切换一个灯泡的开关。直到第 n 轮,你只需要切换最后一个灯泡的开关。

找出并返回 n 轮后有多少个亮着的灯泡。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/bulb-switcher
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题1

思路就是最粗暴的建立一排灯,用一个向量(数列)表示灯的状态,按照题的意思,第一轮切换灯状态,第二轮切换灯的状态,...到第n轮切换灯的状态,最后找出亮灯的数量

class Solution {
public:
    int bulbSwitch(int n) {// 时间复杂度n^2
        vector<int> bulb(n) ;
        for (int i = 0; i < n; i++) {
            bulb[i] = 0;//初始都为关闭,以0表示
        }
        for (int round = 1; round <= n; round++) {
            for (int k = round - 1; k < n; k = k + round) {
                if (bulb[k] == 0) { bulb[k] = 1; }
                else bulb[k] = 0;          
            }
        }
        int lightBulb = 0;
        for (int m = 0; m < n; m++) {  //查找出亮灯的数量
            if (bulb[m] == 1) {
                lightBulb++;
            }
        }
        return lightBulb;
    }    
};

提交后说超出时间限制,最后执行的数据是9999999,时间复杂度太高

解题2

前一种解法太粗暴,需要更快捷的办法,想了想办法,要让灯亮,需要按奇数次

1号灯,不管n多大,1号灯都只会在第一轮被按到,后面都不会按到它所以1号灯整个过程只会按1次,最后它一定是亮着的

2号灯则第一轮会按一次,第二轮又被按一次,之后就不会按到2号灯,所以2号灯一定是熄灭的

再例如12号灯,它会在第1,2,3,4,6,12轮被按到,偶数次,所以12号灯是熄灭的

所以新的解法,就是从1到n号灯,找出每个灯序号的因数个数,因数个数为奇数的序号的灯状态是亮

 1 #include<iostream>
 2 #include<vector>
 3 #include<string>
 4 using namespace std;
 5 
 6 
 7 int intfactor(int number) {   //找因数,返回因数的个数 例如:12的因数 1,2,3,4,6,12
 8     int r = 0;
 9     for (int n = 1; n <= number / 2; n++) {
10         if (number % n == 0)r++;
11     }
12     return r + 1;
13 }
14 
15 class Solution {
16 public:
17     int bulbSwitch(int n) { //因为灯要亮着需要按奇数次,则每个灯泡的序号的因数数量取2的余,余1的是亮的
18         int lightBulb = 0;
19         for (int i = 1; i <= n; i++) {
20             if (intfactor(i) % 2 == 1)lightBulb++;
21         }
22         return lightBulb;
23     }
24 };

本来以为这样会快一点,但是看了下时间复杂度还是n^2,就感觉应该还是过不了,提交果然又超过时间限制,最后执行的数据是99999,说明比第一种解法更垃圾

 

解法3

经历前两种方法的失利,又思考了新的办法,在第二种办法的基础上我试图找找规律

序号   因数

1       

2        1 2

3        1 3 

4        1 2 4    √

5        1 5

6        1 2 3 6 

7        1 7

8        1 2 4 8

9        1 3 9    √

10      1 2 5 10

11      1 11 

12      1 2 3 4 6 12 

13      1 13

14      1 2 7 14

15      1 3 5 15

16      1 2 4 8 16    √

17      1 17

18      1 2 3 6 9 18

..

找到这里我发现了个规律,平方数序号的灯的因数都是奇数,他们最后的状态一定是亮的,思考了下原因,发现因数都是成对的,而平方数的平方根则只有单独的一个

想到这里这个题的解法就很简单了,只需要查找从1到<=n有多少个平方数,就是答案了

#include<iostream>
#include<string>
using namespace std;

class Solution {
public:
    int bulbSwitch(int n) { 
        int lightBulb = 0;
        for (int i = 1; i * i <= n; i++) {//时间复杂度应该为log2n
            lightBulb++;
        }
        return lightBulb;
    }
};

 

总结

三种办法说实话我最喜欢第一种,简单粗暴直接了当,适合我这种不爱思考的懒狗,在内存 cpu摩多摩多的今天,越来越好用,但这只是科技的胜利!

 

第二种第三种也就是在做题的时候会去想,第二种办法想出来的时候,我还觉得我真牛b!结果提交一算,比第一种更垃圾,啊,我真啥b,而且我还不知道哪里不如第一种

 

但第三种办法出来的一瞬间,我认识到了算法的魅力,这是人类的胜利!

 

posted @ 2021-11-15 12:57  xxxd  阅读(154)  评论(0)    收藏  举报