数组元素的最小非零乘积

文章讨论了在给定数组中通过位交换操作,利用贪心策略优先缩小最小元素并增加最大元素,以求得在多次操作后数组乘积的最小非零值。涉及快速幂算法计算效率。题目来源于LeetCode.
摘要由CSDN通过智能技术生成

题目描述

给你一个正整数 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 取余 后返回。

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

1.思路

我们先思考一个简单的问题,假设给定三个正整数 a,b,c,满足 a<b<c,此时需要将某个数缩小 1,另外一个数增加 1,使得 abc 乘积最小,如何选择才是最优选择?

缩小时优先缩小最小的元素:当选择 a 缩小 1 时,此时三者乘积为 (a−1)bc,整体较 abc 缩小了 bc;当选择缩小 c 时,三者乘积为 ab(c−1),整体较 abc 缩小了 ab,此时 ab<bc,因此缩小时优先缩小最小的元素;

增加时优先增加最大的元素:缩小 a 然后选择某个元素进行增加,当选择 b 增加 1 时,此时三者乘积为 (a−1)(b+1)c,整体较 (a−1)bc 增加了 (a−1)c(a-1)c(a−1)c;同理,当选择增加 c 时,增加了 (a−1)b,此时 (a−1)b<(a−1)c,因此增加时优先增加最大的元素。

回到本题,两个数在进行相同的位交换时,本质即将一个元素缩小 2^k,另外一个元素增加 2^k 。根据上述分析,我们可以知道一种贪心思路:进行相同位交换时,优先缩小数组中最小的元素,再增加数组中最大的元素。设当前数组为:[1,2,3,……,2^p-2,2^p-1]。

将1与2^p-1做-(1-1)与+(1-1)操作,2与2^p-3做-(2-1)与+(2-1)操作,……,2^(p-1)-1与2^(p-1)做-(2^(p-1)-1-1)与+(2^(p-1)-1-1)操作,最终得到数组:

[1,1,……,2^p-2,……,2^p-2,2^p-1],乘积为

2.代码

由于幂过大,可以采用快速幂算法进行运算。(读者可以自行学习)

public int minNonZeroProduct(int p) {
        if(p==1)return 1;
        long mod=1000000007;
        long x= fastPow(2,p,mod)-1;
        long y=(long) 1 << (p-1); //不可使用fastPow()方法进行计算,因为该方法会对结果进行模运算
        return (int) ((fastPow(x-1,y-1,mod)*x)%mod);
    }

public long fastPow(long x,long y,long mod){ //快速幂算法,x为底数,y为指数,mod为取模数
        long ans=1;
        long a=x;
        while (y>0){
            if((y&1)!=0)ans=(ans*a)%mod;
            a=a*a%mod;
            y>>=1;
        }
        return ans;
    }

 3.题目参考

. - 力扣(LeetCode)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值