在问 · 算法题解

319. 灯泡开关

题目描述

有 n 个灯泡排成一排,一开始全部是灭的。接下来进行 n 轮操作。

第 1 轮把所有灯泡都打开。第 2 轮把编号为 2 的倍数的灯泡都关掉。从第 3 轮起,第 i 轮把编号为 i 的倍数的灯泡都拨一下开关:亮的变灭,灭的变亮。第 n 轮只拨最后一个灯泡。灯泡从 1 开始编号。

返回 n 轮之后还亮着的灯泡数。

示例 1
输入:n = 3
输出:1

解释:三轮之后依次为 [亮, 亮, 亮]、[亮, 灭, 亮]、[亮, 灭, 灭],只剩 1 个亮着。

示例 2
输入:n = 0
输出:0

解释:没有灯泡。

示例 3
输入:n = 1
输出:1

解释:唯一的灯泡在第 1 轮被打开。

数据范围

  • 0 <= n <= 10^9

解题思路

第 k 个灯泡在第 i 轮被切换,当且仅当 i 整除 k,所以它被切换的次数 = k 的因数个数。因数总是成对出现(d 与 k/d),只有完全平方数的 √k 自己配对,因数个数才是奇数。所以最后亮着的就是 1, 4, 9, … 这些完全平方数,个数为 ⌊√n⌋。

为什么正确

灯泡 k 最终亮 ⇔ k 的因数个数为奇数 ⇔ k 是完全平方数。

复杂度分析

时间 O(1),空间 O(1)。

易错点

n 可达 10^9,直接模拟 O(n log n) 会超时。用浮点 sqrt 时要用整数校正,避免大数时的精度误差。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def bulbSwitch(self, n: int) -> int:
        r = int(n ** 0.5)
        while (r + 1) * (r + 1) <= n:
            r += 1
        while r * r > n:
            r -= 1
        return r

载入编辑器,自己跑一遍 →

数学 专题的其他题目

查看 数学 全部题目 →