Leetcode刷题记录 Day5

每日一题 数组元素的最小非零乘积

给你一个正整数 p 。你有一个下标从 1 开始的数组 nums ,这个数组包含范围 [1, 2^{p}-1]内所有整数的二进制形式(两端都 包含)。你可以进行以下操作 任意 次:

  • 从 nums 中选择两个元素 x 和 y  。
  • 选择 x 中的一位与 y 对应位置的位交换。对应位置指的是两个整数 相同位置 的二进制位。

比方说,如果 x = 1101 且 y = 0011 ,交换右边数起第 2 位后,我们得到 x = 1111 和 y = 0001 。

请你算出进行以上操作 任意次 以后,nums 能得到的 最小非零 乘积。将乘积对 10^{9}+7取余 后返回。

注意:答案应为取余 之前 的最小值。

解题思路

根据题意,nums数组的长度为2的p次方-1,且下标从1开始,即数组的下标与元素值相同。要将x,y对应的位置交换之后存在实际意义也就意味着需要对应位置分别为“0”和“1”,且其他位置不相同。从1到2的p次方减一也意味着每个二进制数最大位数为p,所有数乘积最小就意味着我们要尽可能多的“1”。在草稿过程中我发现,不管如何交换,各个位置上的“0”和“1”的总数是不变的,且都为“2^{p-1}-1”和“2^{p-1}”,而经过转换都可以变为“2^{p-1}-1”个1乘“2^{p-1}-1”个“2^{p-1}-2”再加上“2^{p-1}”,答案好像呼之欲出了。

我直接

return (2**p - 2) ** (2 ** (p-1) - 1) * (2 ** p - 1)

嗯,直到p=3都是正常的,p=4之后就不对了

正当我思路又断了的时候,发现原来题目还有还有个结果求余的操作......这个数比较大一开始用不上,结果写出来之后就给忘了....

代码实现

class Solution:
    def minNonZeroProduct(self, p: int) -> int:
        return (2**p - 2) ** (2 ** (p-1) - 1) * (2 ** p - 1) % (10**9 + 7)

然后发现算到后面竟然超时了!大概是幂运算数字太大了

改一下计算方法就可以了

class Solution:
    def minNonZeroProduct(self, p: int) -> int:
        mod = 10**9 + 7
        return  pow(2 ** p - 2, 2 ** (p - 1) - 1, mod) * (2 ** p - 1) % mod

复杂度分析

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

快速幂

快速幂,二进制取幂(Binary Exponentiation,也称平方法),是一个在O(log n)的时间内计算a^{n}的小技巧,而暴力的计算需要O(n)的时间。这个技巧也常常用在非计算的场景,因为它可以应用在任何具有结合律的运算中。

快速幂 - OI Wiki

随机一题 最少的后缀翻转次数

给你一个长度为 n 、下标从 0 开始的二进制字符串 target 。你自己有另一个长度为 n 的二进制字符串 s ,最初每一位上都是 0 。你想要让 s 和 target 相等。

在一步操作,你可以选择下标 i0 <= i < n)并翻转在 闭区间 [i, n - 1] 内的所有位。翻转意味着 '0' 变为 '1' ,而 '1' 变为 '0' 。

返回使 s  target 相等需要的最少翻转次数。

解题思路

根据题意,我们在执行每次翻转操作时都需要翻转到后缀字符,因此我们只需要从前到后依次翻转就是最小翻转次数了。而只有前后字符不相同时才需要翻转。(官方题例还第一个就挖坑,复杂化你的思路,真doge)

代码实现

class Solution:
    def minFlips(self, target: str) -> int:
        if target == 0:
            return 0
        start = '0'
        ans = 0
        for i in target:
            if i != start:
                ans += 1
                start = i 
        return ans

复杂度分析

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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值