题目难度: 中等
题目描述
初始时有 n 个灯泡关闭。
- 第 1 轮,你打开所有的灯泡。
- 第 2 轮,每两个灯泡你关闭一次。
- 第 3 轮,每三个灯泡切换一次开关(如果关闭则开启,如果开启则关闭)。
- 第 i 轮,每 i 个灯泡切换一次开关。
- 第 n 轮,你只切换最后一个灯泡的开关。
找出 n 轮后有多少个亮着的灯泡。
题目样例
示例 1:
输入
3
输出
1
解释
初始时, 灯泡状态 [关闭, 关闭, 关闭].
- 第一轮后, 灯泡状态 [开启, 开启, 开启].
- 第二轮后, 灯泡状态 [开启, 关闭, 开启].
- 第三轮后, 灯泡状态 [开启, 关闭, 关闭].
你应该返回 1,因为只有一个灯泡还亮着。
题目思考
- 对于轮次 i 而言, 哪些灯泡状态改变取决于其下标是否为 i 的倍数
- 由此可得, 最终开着的灯泡应该有奇数个因子, 这样才能保证最终状态是开着的. 因为如果有偶数个因子的话, 每次开和关都和原状态一致, 而最初又是关着的, 那么最终也会是关着的.
- 进一步思考: 什么数的因子个数为奇数?
解决方案
方案 1
思路
- 最 naive 的方法, 根据上面思考, 求每个下标的因子个数, 统计有奇数因子的下标即可
- 注意: 因为复杂度过高, 会 TLE, 所以这个方案只是作为推导下面更优方案的基础…
复杂度
- 时间复杂度 O(N*sqrt(N)): 需要遍历每个下标, 而每个下标求因子数需要遍历到它的平方根
- 空间复杂度 O(1): 只使用了几个变量
代码
Python 3
class Solution: def bulbSwitch(self, n: int) -> int: def getFactorCount(num): res = 0 for i in range(1, int(math.sqrt(num)) + 1): if num % i == 0: res += 1 if i == num // i else 2 return res res = 0 for num in range(1, n + 1): if getFactorCount(num) & 1: res += 1 return res
C++
class Solution { private: int getFactorCount(int num) { int res = 0; for (int i = 1; i <= int(sqrt(num)); ++i) { if (num % i == 0) { res += i == num / i ? 1 : 2; } } return res; } public: int bulbSwitch(int n) { int res = 0; for (int num = 1; num <= n; ++num) { if (getFactorCount(num) & 1) { ++res; }; } return res; } };
方案 2
思路
- 回顾因子是怎么计算的: i*(n/i), 通常因子都是成对的, 只有存在 i<mark>n/i 时才会是单独一个因子, 即</mark>>平方数
- 如何快速求平方数? 只需要将平方根 i 从 1 开始循环, 当其平方大于 n 时退出即可, 此时的 i-1 即为所求
复杂度
- 时间复杂度 O(sqrt(N)): 只需要遍历 N 的平方根个数
- 空间复杂度 O(1): 只使用了几个变量
代码
Python 3
class Solution: def bulbSwitch(self, n: int) -> int: i = 1 while i * i <= n: i += 1 return i - 1
C++
class Solution { public: int bulbSwitch(int n) { int i = 1; while (i * i <= n) { ++i; } return i - 1; } };
方案 3
思路
- 进一步思考: 观察方案 2 的代码, 是不是很熟悉?
- 没错! 最终结果其实就是 int(sqrt(n))…
- 所以一行代码搞定
复杂度
- 时间复杂度 O(M(n)): 只需要调用 sqrt 即可, sqrt 根据语言/平台/硬件的不同, 其复杂度也不一样, 简单来说可认为和一次除法的复杂度差不多…感兴趣的话可参考Computational complexity of mathematical operations
- 这里 M 是指乘法算法的复杂度, M 根据实现的不同, 其复杂度介于 nlogn 到 n^2 之间, n 是数字的位数不是数字本身…
- 空间复杂度 O(1): 只使用了几个变量
代码
Python 3
class Solution: def bulbSwitch(self, n: int) -> int: return int(math.sqrt(n))
C++
class Solution { public: int bulbSwitch(int n) { return int(sqrt(n)); } };
我的公众号: 每日精选算法题, 欢迎大家扫码关注~😊