2026-04-26使循环数组余额非负的最少移动次数。用go语言给定一个环形排列的数组 balance长度为 n其中 balance[i] 表示第 i 个人当前的净余额正数代表有剩余负数代表欠债。在一次操作中你可以选择某个人把恰好 1 单位余额转给他的左邻居或右邻居因为是环形首尾相邻。目标通过若干次这样的转移使得所有位置的余额都变为非负即每个人都不再欠债。要求输出实现该目标的最小操作次数如果从初始状态出发无法做到则输出 -1。已知条件初始时数组中最多只有一个位置的余额为负。1 n balance.length 100000。-1000000000 balance[i] 1000000000。balance 中初始至多有一个负值。输入balance [1,2,-5,2]。输出6。解释一种最优的移动序列如下从 i 1 移动 1 个单位到 i 2结果 balance [1, 1, -4, 2]从 i 1 移动 1 个单位到 i 2结果 balance [1, 0, -3, 2]从 i 3 移动 1 个单位到 i 2结果 balance [1, 0, -2, 1]从 i 3 移动 1 个单位到 i 2结果 balance [1, 0, -1, 0]从 i 0 移动 1 个单位到 i 1结果 balance [0, 1, -1, 0]从 i 1 移动 1 个单位到 i 2结果 balance [0, 0, 0, 0]因此所需的最小移动次数是 6。题目来自力扣3776。代码执行过程详细拆解第一步遍历数组统计核心信息计算数组所有元素的总和12(-5)2 0遍历过程中记录唯一的负数位置只有索引2的值是-5因此negIdx2基础校验总和0 ≥ 0满足可以完成的条件存在负数需要计算移动次数。第二步确定核心需求负数位置是索引2余额为-5需要补充5单位余额才能变成0非负记need5需要的总余额数。初始化总操作次数ans0。第三步按距离分层收集余额环形就近原则最小步数因为是环形数组我们从离负数位置最近的地方开始收集余额距离越近移动步数越少符合最小操作次数要求距离从1开始依次递增距离 dis1离索引2最近的左右邻居找环形数组中距离negIdx2为1的两个位置左邻居(2-14)%4 1右邻居(21)%4 3这两个位置的余额索引12索引32总和s224计算当前需要5单位这两个位置能提供4单位全部用完操作次数 4 × 14个单位每个移动1步→ ans4剩余需要的余额need5-41距离 dis2下一层更远的位置找环形数组中距离negIdx2为2的两个位置左邻居(2-24)%4 0右邻居(22)%4 0环形数组距离2时左右是同一个位置这个位置的余额索引01总和s1计算剩余只需要1单位这个位置恰好能提供1单位操作次数 1 × 21个单位每个移动2步→ ans426need0需求满足结束计算第四步返回结果总操作次数为6与题目示例输出一致。时间复杂度与额外空间复杂度分析1. 时间复杂度第一步遍历数组执行了n次操作n是数组长度第三步按距离收集余额因为最多只有1个负数且我们是就近收集循环次数远小于n可以视为常数次整体总操作次数与数组长度n成正比 →时间复杂度为 O(n)。2. 额外空间复杂度代码中只定义了total、negIdx、need、ans、dis、s等常数个变量没有创建任何与数组长度n相关的额外数组、集合等数据结构额外空间复杂度为 O(1)常数级空间。总结执行核心流程统计总和→定位唯一负数→校验合法性→就近分层收集余额→累加步数→返回结果时间复杂度O(n)线性复杂度适合题目n≤100000的大数据量额外空间复杂度O(1)仅使用固定变量无额外内存开销。Go完整代码如下packagemainimport(fmt)funcminMoves(balance[]int)int64{total:0negIdx:-1fori,x:rangebalance{totalxifx0{negIdxi}}iftotal0{// 总和必须非负return-1}ifnegIdx0{// 没有负数无需操作return0}n:len(balance)need:-balance[negIdx]ans:0fordis:1;;dis{// 把与 negIdx 相距 dis 的数移到 negIdxs:balance[(negIdx-disn)%n]balance[(negIdxdis)%n]ifsneed{ansneed*dis// need 个 1 移动 dis 次returnint64(ans)}anss*dis// s 个 1 移动 dis 次need-s}}funcmain(){balance:[]int{1,2,-5,2}result:minMoves(balance)fmt.Println(result)}Python完整代码如下# -*-coding:utf-8-*-fromtypingimportListdefminMoves(balance:List[int])-int:total0neg_idx-1fori,xinenumerate(balance):totalxifx0:neg_idxiiftotal0:# 总和必须非负return-1ifneg_idx0:# 没有负数无需操作return0nlen(balance)need-balance[neg_idx]ans0dis1whileTrue:# 把与 neg_idx 相距 dis 的数移到 neg_idxleftbalance[(neg_idx-dis)%n]rightbalance[(neg_idxdis)%n]sleftrightifsneed:ansneed*dis# need 个 1 移动 dis 次returnans anss*dis# s 个 1 移动 dis 次need-s dis1if__name____main__:balance[1,2,-5,2]resultminMoves(balance)print(result)C完整代码如下#includeiostream#includevector#includecmathusingnamespacestd;longlongminMoves(vectorintbalance){inttotal0;intnegIdx-1;for(inti0;ibalance.size();i){totalbalance[i];if(balance[i]0){negIdxi;}}if(total0){// 总和必须非负return-1;}if(negIdx0){// 没有负数无需操作return0;}intnbalance.size();intneed-balance[negIdx];longlongans0;for(intdis1;;dis){// 把与 negIdx 相距 dis 的数移到 negIdxintleftbalance[(negIdx-disn)%n];intrightbalance[(negIdxdis)%n];intsleftright;if(sneed){ansstatic_castlonglong(need)*dis;// need 个 1 移动 dis 次returnans;}ansstatic_castlonglong(s)*dis;// s 个 1 移动 dis 次need-s;}}intmain(){vectorintbalance{1,2,-5,2};longlongresultminMoves(balance);coutresultendl;return0;}