LeetCode 2033. 获取单值网格的最小操作数【详细技术解析】
一、题目描述
给你一个大小为m x n的二维整数网格grid和一个整数x。每一次操作,你可以对grid中的任一元素加 x或减 x。
单值网格:指网格中全部元素都相等的网格。
要求返回使网格化为单值网格所需的最小操作数。如果无法实现,返回\-1。
题目示例
示例 1:
输入:grid = [[2,4],[6,8]], x = 2
输出:4
解释:将所有元素统一为 4。2+2(1次)、6-2(1次)、8-2*2(2次),总操作数 4。
示例 2:
输入:grid = [[1,5],[2,3]], x = 1
输出:5
解释:将所有元素统一为 3,累计操作次数最少为5。
示例 3:
输入:grid = [[1,2],[3,4]], x = 2
输出:-1
解释:元素差值无法被x整除,无法统一为相同值。
题目约束
m == grid\.length,n == grid\[i\]\.length1 \<= m, n \<= 10^51 \<= m \* n \<= 10^5(总元素数不超过10万,时间复杂度可接受O(NlogN))1 \<= x, grid\[i\]\[j\] \<= 10^4
二、核心解题思路分析
1. 可行性判断(关键前提)
每次操作只能对元素加x/减x,因此任意两个元素的差值,必须是x的整数倍,否则永远无法通过操作使所有元素相等。
推导:假设基准值为target,任意元素num满足\(num \- target\) % x == 0。可等价推导为:所有元素对 x 的余数必须完全相同。
若存在任意元素的余数与首个元素余数不同,直接返回\-1。
2. 最小操作数的数学原理
当所有元素可统一时,问题转化为:寻找一个目标值,使所有元素转换到该值的操作次数总和最小。
操作次数公式:单个元素num转为target的操作次数 =abs\(num \- target\) // x。
根据绝对值距离最小值定理:一组有序数字中,所有数字到中位数的绝对值距离之和最小。因此最优目标值为数组的中位数。
3. 整体解题步骤
将二维网格展平为一维数组,方便统一处理;
遍历数组,校验所有元素对
x的余数是否一致,不一致直接返回-1;对一维数组进行排序,找到中位数;
遍历所有元素,累计转换到中位数的总操作次数,返回结果。
三、完整代码实现(带详细注释)
严格遵循题目要求的代码格式,适配LeetCode提交标准,包含完整注释、边界处理:
fromtypingimportListclassSolution:defminOperations(self,grid:List[List[int]],x:int)->int:# 1. 将二维网格展平为一维数组nums=[]forrowingrid:nums.extend(row)# 2. 获取首个元素的余数,作为校验基准remainder=nums[0]%x# 3. 遍历所有元素,校验余数是否统一fornuminnums:ifnum%x!=remainder:# 余数不统一,无法构成单值网格return-1# 4. 数组排序,寻找中位数nums.sort()mid=len(nums)//2target=nums[mid]# 5. 计算所有元素转换为中位数的最小操作次数res=0fornuminnums:# 差值整除x即为当前元素需要的操作次数res+=abs(num-target)//xreturnres四、代码优化版本(精简高效)
在不改变时间复杂度的前提下,精简代码逻辑,减少冗余遍历,适配大数据量场景:
fromtypingimportListclassSolution:defminOperations(self,grid:List[List[int]],x:int)->int:# 一行代码展平二维数组nums=[numforrowingridfornuminrow]base_mod=nums[0]%x# 合法性校验ifany(num%x!=base_modfornuminnums):return-1# 排序取中位数,计算总操作数nums.sort()median=nums[len(nums)//2]returnsum(abs(n-median)//xforninnums)五、逐案例代码解析
案例1:grid = [[2,4],[6,8]], x = 2
1. 展平数组:\[2,4,6,8\],基准余数2%2=0,所有元素余数均为0,合法;
2. 排序后数组不变,长度为4,中位数下标为2,目标值6?修正:长度4,下标4//2=2,元素为6,也可选取4,两者总操作数一致;
3. 计算次数:|2-4|/2 + |4-4|/2 + |6-4|/2 + |8-4|/2 = 1+0+1+2 = 4,与输出结果一致。
案例3:grid = [[1,2],[3,4]], x = 2
1. 展平数组:\[1,2,3,4\],基准余数1%2=1;
2. 元素2%2=0,余数不匹配,直接返回-1,符合题意。
六、复杂度分析
时间复杂度:O(N log N)
N 为网格总元素数(N = m\*n)。主要耗时为数组排序操作,时间复杂度为 O(N log N);两次遍历数组为 O(N),可忽略。根据题目约束 N ≤ 10^5,该复杂度完全AC。
空间复杂度:O(N)
需要额外一维数组存储所有网格元素,空间复杂度为元素总数 N。若允许修改原数组,可原地优化,但可读性会下降。
七、易错点总结
易错点1:直接使用平均值作为目标值。平均值适用于平方和最小,而本题是绝对值和最小,必须使用中位数,否则会导致结果错误。
易错点2:仅校验首尾元素差值,未校验所有元素余数。必须保证全部元素余数一致,否则存在无法统一的元素。
易错点3:使用浮点数计算操作次数。必须用整数整除
//,避免浮点精度误差。
八、总结
本题是数学贪心+数组排序的经典题型,核心考点分为两点:一是通过余数校验判断问题可行性,二是利用中位数的数学性质求解最小操作次数。解题逻辑清晰,代码简洁,是算法面试中高频的简单贪心题型,熟练掌握中位数最值原理即可快速解题。