2026-01-20的LeetCode周赛430,我印象最深的不是压轴题,反而是这道编号3314的“构造最小位运算数组I”。看到“位运算”和“构造”两个词凑在一起,我第一反应是又要被按位操作折磨了,结果静下心推了十分钟才发现,这题的思路可以说是周赛里少见的“纸老虎”:核心不是复杂公式,而是能不能想到“把必须为1的位先铺下去,再统一检查”。这篇文章我就把当时的完整推导、代码落地和赛后复盘写下来,给同样被位运算构造题搞到头大的朋友一个参考。适合三类人看:每周打周赛的选手、正在准备面试位运算专题的人、以及想搞懂“逐位思考”这种底层方法的人。
先交代一下我对题面的理解。给定一个长度为n的非负整数数组nums,要求构造一个长度为n+1的非负整数数组arr,使得对每个下标i,都满足 nums[i] = arr[i] & arr[i+1]。如果存在多个合法的arr,返回数值最小的那个;如果不存在合法构造,返回[-1]。题名里的“I”意味着这是系列第一题,通常这种带编号的题,第一版都会把约束搞得比较温和,重点考验基础思维而不是刁钻算法。
1. 题目到底在说什么:一个按位与的逆向构造问题
1.1 从等式结构看约束关系
先看清数据形态。nums有n个元素,arr却有n+1个元素,也就是说nums的每个元素对应arr中相邻两个元素的一次“按位与”。这是个典型的链式结构:arr[0]和arr[1]一起决定nums[0],arr[1]和arr[2]一起决定nums[1],以此类推。中间位置的arr[i]会同时出现在两个等式里,它既要配合左边满足nums[i-1],又要配合右边满足nums[i],这是整道题最难处理的地方。
如果只要求“找一个可行解”,事情其实很简单:把arr所有位置都设成全1,或者设成INT_MAX,然后逐个等式去凑。但题目要求的是所有合法解中的最小值,这就完全变了性质。你必须在每个二进制位上精确控制0和1的分布,任何多余的1都会让结果变大,而缺少必要的1又会让等式不成立。
1.2 先手推几个小例子找感觉
我建议所有读这篇文章的人,看到这类题都先手推两个例子再想算法。拿最简单的 nums = [1] 来说,arr长度是2,需要 arr[0] & arr[1] = 1。按位与要得到最低位的1,必须两个数的最低位都是1,所以arr[0]和arr[1]都至少是1,答案就是[1,1]。
再看一个稍微长一点的 nums = [2,0]。arr长度为3。第一个等式要求arr[0]和arr[1]的二进制第1位(也就是值为2的那一位)都必须是1;第二个等式要求arr[1]和arr[2]的与结果是0,但arr[1]已经被前一个等式逼着在第1位是1了,想让arr[1] & arr[2]的第1位变成0,唯一办法是让arr[2]的第1位为0。于是可以构造 arr = [2,2,0],验证:2 & 2 = 2,2 & 0 = 0,完全正确。
也可以举一个无解的例子。nums = [2,1,2] 就无解。第一个等式把arr[0]和arr[1]的第1位都钉死为1,第三个等式把arr[2]和arr[3]的第1位都钉死为1,结果中间那个等式 arr[1] & arr[2] = 1 要求第1位必须是0,但arr[1]和arr[2]的第1位都被钉成了1,矛盾。这个例子在我后面讲两阶段验证法时会反复用到。
1.3 “最小”二字带来的关键转变
如果把题目的“最小”拿掉,一个很自然的暴力做法是:枚举arr所有可能取值,检查是否满足所有等式,然后取最小值。但arr是非负整数数组,取值范围太大,显然不可能枚举。
“最小”这两个字真正的价值,是逼着你去思考一个更本质的问题:每个二进制位上的1,哪些是躲不掉的?哪些是可以不存在的?只要能把“躲不掉的1”全部找出来,并且确认它们之间没有冲突,剩下的位全部填0,得到的就是最小解。这也是整个解法最核心的直觉。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
