寻求最少移位的原地数组压缩算法
实现最少移动量的Lua数组压缩算法
要实现最少元素移动次数的数组压缩(用-1标记空值),核心思路是用双指针法精准填补前面的空位,避免不必要的元素移动。具体逻辑如下:
- 用左指针
left跟踪第一个未被填补的空位(值为-1的位置) - 用右指针
right从left的下一位开始遍历,找到第一个非-1的元素 - 找到后将该元素移动到
left位置,把原位置设为-1,然后left右移一位(因为这个空位已经被填补) - 重复上述过程直到遍历结束,最后清理数组末尾的所有-1(设为nil,保证Lua数组的正常迭代)
这种方法的移动次数是最少的——每个非-1元素最多被移动一次,只有当它需要填补前面的空位时才会被移动,完全符合你给出的示例效果。
Lua代码实现
local function compact(arr) local left = 1 local len = #arr -- 第一步:填补前面的空位 while left <= len do -- 找到第一个空位 while left <= len and arr[left] ~= -1 do left = left + 1 end -- 从left之后找第一个非-1元素 local right = left + 1 while right <= len and arr[right] == -1 do right = right + 1 end -- 如果没有找到可移动的元素,结束循环 if right > len then break end -- 移动元素到空位,原位置设为-1 arr[left] = arr[right] arr[right] = -1 left = left + 1 end -- 第二步:清理末尾的-1,设为nil local last_valid = 0 for i = 1, len do if arr[i] ~= -1 then last_valid = i else break -- 前面的空位已被填补,后续都是连续的-1 end end -- 截断数组,把后面的元素设为nil for i = last_valid + 1, len do arr[i] = nil end end -- 测试示例 local arr = {1,3,4,-1,6,-1,8,-1,-1} compact(arr) -- 输出结果:{1,3,4,8,6} for k, v in ipairs(arr) do print(v) end
效果说明
拿你的示例来看:
- 初始
left停在索引4(值为-1),right找到索引7的8,将8移到4的位置,7设为-1,left移到5 - 索引5的值是6(非-1),
left继续移到6,此时right从7开始找,后面都是-1,循环结束 - 最后清理时,从索引6开始都是-1,所以设为nil,最终数组就是
{1,3,4,8,6},只移动了1次元素,完全符合预期。
相比反向遍历的方法,这种双指针法不会盲目移动所有元素,而是只针对性填补前面的空位,最大化减少移动次数,同时时间复杂度保持O(N),满足你的要求。
内容的提问来源于stack exchange,提问作者KayleMaster
相关产品推荐
相关产品推荐

