题目难度: 中等
题目描述
初始时有 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), 通常因子都是成对的, 只有存在 in/i 时才会是单独一个因子, 即>平方数
- 如何快速求平方数? 只需要将平方根 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));
}
};
我的公众号: 每日精选算法题, 欢迎大家扫码关注~😊