灯泡开关
原题 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 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,而且我还不知道哪里不如第一种
但第三种办法出来的一瞬间,我认识到了算法的魅力,这是人类的胜利!
浙公网安备 33010602011771号