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

最小非零乘积:LeetCode 第 1969 题深度解析


📘 题目描述

给你一个正整数 p,你需要构建一个下标从 1 开始的数组 nums,其中包含范围 [1, 2^p - 1] 内的所有整数(包括两端),并将这些数字的二进制形式看作可以任意操作的“位块”。

你可以执行如下操作任意次:

  • nums 中选择两个元素 xy
  • 选择它们中对应位置的某一位进行交换(即,如果 x 和 y 的二进制表示在第 i 位上分别是 ab,你可以让它们互换这一位的值)。

你的任务是:在任意次此类操作后,使 nums 中所有元素的乘积为最小的非零值,并返回结果对 10^9 + 7 取余后的值。


🧠 解题分析

📌 操作的本质

看似复杂的交换操作,其实是对数组中所有数字的二进制位进行重新分配。你可以无限次交换任意两个数在某一位上的值——这意味着在每个“二进制位”的层面上,所有数位是全局共享的,你可以任意重新分布它们

关键点是:

  • 每一位上有多少个 10 是固定的;
  • 但你可以把这些 10 分配给任意数字的任意位。

也就是说:在操作完成后,我们可以控制每个数的二进制位,使其构成你希望的任意模式(只要各位上 1 的个数总和不变)。


🎯 解题方法

我们想要使乘积最小化,且必须非零。既然可以控制二进制位的分布,我们要在合法的数字(范围是 [1, 2^p - 1])中选择一种组合,使得乘积最小。

🎯 重要观察:

数组 nums 中包含的数字为:

[1,2,3,…,2p−1][1, 2, 3, …, 2^p - 1]

它有总共有 n = 2^p - 1 个元素。

我们做以下几个定义:

  • max_num = 2^p - 1nums 中最大的数,也是所有位都是 1 的数字;
  • base = max_num - 1 = 2^p - 2 是第二大的数;
  • 其余 n - 1 = base 个数可以进行配对。

关键策略:

  • 保留一个 max_num 不变;
  • 剩下的 base = 2^p - 2 个数可以构造成 base,并两两一组(因为总是偶数);
  • 每组的乘积为 (2^p - 2)^2,所以总的乘积是:

((2p−2)(2p−2)/2)×(2p−1)\left((2^p - 2){(2p - 2)/2}\right) \times (2^p - 1)

最后对 10^9 + 7 取模即可。


✅ Python 解法

class Solution:
    def minNonZeroProduct(self, p: int) -> int:
        MOD = 10**9 + 7
        max_num = (1 << p) - 1        # 2^p - 1
        base = max_num - 1            # 2^p - 2
        exp = base // 2               # (2^p - 2) // 2
        return (pow(base, exp, MOD) * max_num) % MOD

🧮 示例说明

示例 1:

输入:

p = 1

计算:

  • nums = [1]
  • 乘积就是 1,自然最小。

输出:1


示例 2:

输入:

p = 2

nums = [1, 2, 3],所有组合要么不能变更,要么保持原始乘积。

  • 原始乘积:1 * 2 * 3 = 6

输出:6


示例 3:

输入:

p = 3
  • nums = [1, 2, 3, 4, 5, 6, 7]
  • max_num = 7
  • base = 6,exp = 3

计算:

(6^3 * 7) % MOD = 216 * 7 = 1512

输出:1512


⏱️ 复杂度分析

项目复杂度
时间复杂度O(log p)
空间复杂度O(1)

快速幂运算复杂度是 O(log e),即指数的位数。


🔍 比较与分析

方法描述复杂度是否满足题意
枚举法遍历所有排列,计算乘积指数级❌ 时间超限
贪心构造只保留一个最大值,其余统一为次大值O(log p)✅ 最优解
暴力模拟交换位太多无用操作不可行❌ 超时

最终,我们用数学归纳 + 快速幂计算找到了这道题的最优解。


🧾 总结

这道题是一道非常典型的数学构造 + 位操作建模问题,核心在于:

  • 抽象交换操作的意义;
  • 利用二进制位的对称性和全局可控性;
  • 构造数学表达式,结合快速幂求解。

不仅锻炼了对位运算和数论的理解,也要求具备较强的建模能力。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值