贪心+位运算,LeetCode 1969. 数组元素的最小非零乘积

本文介绍了一道关于计算在给定整数范围内,通过有限次位交换操作使数组元素乘积最小的题目。思路是将数组分为两个部分,利用配对原则和保留最低位1的优势得出最优解。解题复杂度为O(p)。
摘要由CSDN通过智能技术生成

一、题目

1、题目描述

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

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

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

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

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

2、接口描述

class Solution {
public:
typedef long long LL;
LL mod = 1e9 + 7;
    LL qp(LL a, LL b){
        a %= mod;
        LL ret = 1;
        while(b){
            if(b & 1) ret = ret * a % mod;
            b >>= 1, a = a * a % mod;
        }
        return ret;
    }
    int minNonZeroProduct(LL p) {
        LL k = (1LL << p) - 1;
        return k % mod * qp(k - 1, k >> 1) % mod;
    }
};

3、原题链接

1969. 数组元素的最小非零乘积


二、解题报告

1、思路分析

任给两个数a,b,不妨设a < b,a给b1是否能让a * b变小呢?

我们不妨设a = x + 2 ^ k,b = y,(y的第k位为0)

那么交换前有a * b = xy + y * 2 ^ k

交换后a = x,b = y + 2 ^ k,a *b = xy + x * 2 ^ k

由于x < y,所以结果变小

然后对于[1, 2 ^ p - 1]这2 ^ p - 1个数字,我们可以分为[1, 2 ^ (p - 1) - 1],[2 ^ (p - 1), 2 ^ p - 2],2 ^ p - 1

我们发现[1, 2 ^ (p - 1) - 1],[2 ^ (p - 1), 2 ^ p - 2]可以配成偶数对没有相同1的数对,而且两两相加为2 ^ p - 1

如p = 3,则可分为[1, 2, 3]、[4, 5, 6]、7

1 + 6 = 7,2 + 5 = 7,3 + 4 = 7,左边区间可以将除最低位1外的所有1都给右边,于是得到

1,1,1,6,6,6,7

不难证明左边区间保留最低位1时比保留其它位1更优

于是给定p,我们的答案就是 (2 ^ p - 1) * pow(2 ^ p - 2, 2 ^ (p - 1) - 1)

2、复杂度

时间复杂度:O(p) 空间复杂度:O(1)

3、代码详解

​cpp
class Solution {
public:
typedef long long LL;
LL mod = 1e9 + 7;
    LL qp(LL a, LL b){
        a %= mod;
        LL ret = 1;
        while(b){
            if(b & 1) ret = ret * a % mod;
            b >>= 1, a = a * a % mod;
        }
        return ret;
    }
    int minNonZeroProduct(LL p) {
        LL k = (1LL << p) - 1;
        return k % mod * qp(k - 1, k >> 1) % mod;
    }
};
python3
class Solution:
    def minNonZeroProduct(self, p: int) -> int:
        MOD = 1_000_000_007
        k = (1 << p) - 1
        return k * pow(k - 1, k >> 1, MOD) % MOD

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EQUINOX1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值