​LeetCode刷题实战319:灯泡开关

算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !

今天和大家聊的问题叫做 灯泡开关,我们先来看题面:

https://leetcode-cn.com/problems/bulb-switcher/

There are n bulbs that are initially off. You first turn on all the bulbs, then you turn off every second bulb.

On the third round, you toggle every third bulb (turning on if it's off or turning off if it's on). For the ith round, you toggle every i bulb. For the nth round, you only toggle the last bulb.

Return the number of bulbs that are on after n rounds.

初始时有 n 个灯泡处于关闭状态。

对某个灯泡切换开关意味着:如果灯泡状态为关闭,那该灯泡就会被开启;而灯泡状态为开启,那该灯泡就会被关闭。

第 1 轮,每个灯泡切换一次开关。即,打开所有的灯泡。

第 2 轮,每两个灯泡切换一次开关。即,每两个灯泡关闭一个。

第 3 轮,每三个灯泡切换一次开关。

第 i 轮,每 i 个灯泡切换一次开关。而第 n 轮,你只切换最后一个灯泡的开关。

找出 n 轮后有多少个亮着的灯泡。

示例

解题

https://www.acwing.com/solution/content/20256/

问题转化为求1~n有多少个数字的约数个数为奇数个。

解法一

联想到提高课中“轻拍牛头”那道题,可以反着求每个数的约数个数。对于1~n中的某一个数i,枚举它的所有倍数,计算他对它的倍数约数个数的贡献。

时间复杂度分析

(n/1)+(n/2)+(n/3)+…+(n/n)=nlogn

class Solution:
    def bulbSwitch(self, n: int) -> int:
        h = [0 for i in range(n + 1)]
        for i in range(1, n + 1):
            j = 1
            while i * j <= n:
                h[i * j] += 1
                j += 1
        res = 0
        for i in range(1, n + 1):
            if h[i] % 2 == 1:
                res += 1
        return res;

解法二

有这样的结论:一个数字的约数个数是奇数个等价于这个数字是完全平方数

证明必要性

如果n是完全平方数,那么除了(√n)×(√n)(n)×(n),其余的约数对均包含两个数字,因此完全平方数有奇数个约数。

证明充分性

约数个数的问题常常会和质因子分解结合在一起,设:

n=pa11×pa22×…×pakk

n=p1a1×p2a2×…×pkak

因此约数个数为(a1+1)×…×(ak+1)(a1+1)×…×(ak+1),又因为约数个数为奇数个,因此a1…aka1…ak都必须是偶数,所以n可以写作:

n=(pa121×pa222×…×pak2k)2

n=(p1a12×p2a22×…×pkak2)2

因此n是完全平方数。

证明了这个结论之后原问题就等价于1~n中有多少个完全平方数,代码为:

class Solution:
    def bulbSwitch(self, n: int) -> int:
        return int(sqrt(n))

好了,今天的文章就到这里,如果觉得有所收获,请顺手点个在看或者转发吧,你们的支持是我最大的动力 。

上期推文:

LeetCode1-300题汇总,希望对你有点帮助!

LeetCode刷题实战301:删除无效的括号

LeetCode刷题实战302:包含全部黑色像素的最小矩阵

LeetCode刷题实战303:区域和检索 - 数组不可变

LeetCode刷题实战304:二维区域和检索 - 矩阵不可变

LeetCode刷题实战305:岛屿数量II

LeetCode刷题实战306:累加数

LeetCode刷题实战307:区域和检索 - 数组可修改

LeetCode刷题实战308:二维区域和检索 - 可变

LeetCode刷题实战309:最佳买卖股票时机含冷冻期

LeetCode刷题实战310:最小高度树

LeetCode刷题实战311:稀疏矩阵的乘法

LeetCode刷题实战312:戳气球

LeetCode刷题实战313:超级丑数

LeetCode刷题实战314:二叉树的竖直遍历

LeetCode刷题实战315:计算右侧小于当前元素的个数

LeetCode刷题实战316:去除重复字母

LeetCode刷题实战317:离建筑物最近的距离

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值