灯泡开关

2019-05-31  本文已影响0人  我要扭开奥利奥

灯泡开关

在这个问题中,我们能够首先想到的就是使用暴力模拟。根据模拟可以直接模拟每一步的操作。但是这会发生TLE错误,分析时间复杂度。第一次会进行n次操作,第二次进行n/2次操作,第三次进行n/3次操作......因此总的时间复杂度为\frac{n}{1} + \frac{n}{2} + \frac{n}{3} + ...... + \frac{n}{n} \\ =n(\frac{1}{1} + \frac{1}{2} + \frac{1}{3} + ...... + \frac{1}{n})\\ =n \times ( \ln n + c)
其中C为欧拉常数,为0.5772...,虽然看起来这个只是一个n \ln (n)的时间复杂度,但是在10000000的时候就会TLE。
使用代码如下:

public int bulbSwitch(int n){
        // 有效区间1到n+1,便于模拟
        int[] bulbs = new int[n+1];
        for(int i = 1;i <= n;i++){
            int j = 1;
            int k = j*i;
            while (k <= n){
                bulbs[k] = bulbs[k]^1;  //使用异或操作,安慰自己这样会快一些不会发生TLE
                j++;
                k = j*i;
            }
        }
        int res = 0;
        for(int i = 1;i <= n;i++){
            res += bulbs[i]==0 ? 0:1;
        }
        return res;
    }

因此,我们应该像一个方法来解决超时的问题,一般解决思路是空间换时间,另一种是使用数学方法或找规律。
现在我们在n=5的时候进行模拟,我们用1表示开,0表示关,可以看到以下结果:

public int bulbSwitch(int n){
        int res = 0;
        while (res * res <= n) res++;
        return res;
    }
//更好的解法
public int bulbSwitch(int n){
        return (int)Math.sqrt(n);
    }
上一篇 下一篇

猜你喜欢

热点阅读