Medium

题目描述

有 n 个灯泡,开始时都处于关闭状态。你首先打开所有的灯泡,然后关闭每第二个灯泡。

第三轮,你切换每第三个灯泡(如果关闭则打开,如果打开则关闭)。第 i 轮,你切换每第 i 个灯泡。第 n 轮,你只切换最后一个灯泡。

返回 n 轮后有多少个灯泡亮着。

示例 1:

输入:n = 3
输出:1
解释:
初始时,三个灯泡的状态 [关闭, 关闭, 关闭]。
第一轮后,三个灯泡的状态 [打开, 打开, 打开]。
第二轮后,三个灯泡的状态 [打开, 关闭, 打开]。
第三轮后,三个灯泡的状态 [打开, 关闭, 关闭]。 
你应该返回 1,因为只有一个灯泡还亮着。

示例 2:

输入:n = 0
输出:0

示例 3:

输入:n = 1
输出:1

提示:

  • 0 <= n <= 10^9

解题思路

这道题看似复杂,但实际上有一个非常巧妙的数学规律。

我们来分析每个灯泡被切换的次数。对于第 i 个灯泡(1 ≤ i ≤ n),它会在第 j 轮被切换,当且仅当 j 能整除 i。换句话说,第 i 个灯泡被切换的次数等于 i 的因数个数。

关键观察:一个数的因数通常是成对出现的。例如,12 的因数有 1×12、2×6、3×4,所以因数个数为偶数。但是完全平方数是例外,比如 9 的因数有 1×9、3×3,其中 3×3 只算一个因数,所以完全平方数的因数个数为奇数。

由于灯泡初始状态为关闭,被切换奇数次后会亮着,偶数次后仍然关闭。因此,只有编号为完全平方数的灯泡最终会亮着。

问题转化为:在 1 到 n 中有多少个完全平方数?答案就是 ⌊√n⌋(n 的平方根的整数部分)。

这个解法的时间复杂度为 O(1),空间复杂度为 O(1),非常高效。

代码实现

class Solution {
public:
    int bulbSwitch(int n) {
        return sqrt(n);
    }
};
class Solution:
    def bulbSwitch(self, n: int) -> int:
        return int(n ** 0.5)
public class Solution {
    public int BulbSwitch(int n) {
        return (int)Math.Sqrt(n);
    }
}
/**
 * @param {number} n
 * @return {number}
 */
var bulbSwitch = function(n) {
    return Math.floor(Math.sqrt(n));
};

复杂度分析

复杂度类型复杂度
时间复杂度O(1)
空间复杂度O(1)

相关题目