2026-04-06:字典序最小和为目标值且绝对值是排列的数组。用go语言,给你一个正整数 n 和一个整数 target。 你需要构造一个长度为 n 的整数数组,要求同时满足: 1.数组中所有元素的总

张开发
2026/4/6 2:20:46 15 分钟阅读

分享文章

2026-04-06:字典序最小和为目标值且绝对值是排列的数组。用go语言,给你一个正整数 n 和一个整数 target。 你需要构造一个长度为 n 的整数数组,要求同时满足: 1.数组中所有元素的总
2026-04-06字典序最小和为目标值且绝对值是排列的数组。用go语言给你一个正整数 n 和一个整数 target。你需要构造一个长度为 n 的整数数组要求同时满足1.数组中所有元素的总和必须等于 target。2.把数组里每个元素取绝对值以后得到的这 n 个数必须是 1,2,…,n 的某种排列也就是每个数 1 到 n 都恰好出现一次顺序可以不同。3.若不存在满足上述条件的数组则返回一个空数组 []。另外在所有满足条件的数组里你要返回字典序最小的那个。字典序比较规则对任意两个数组 a 和 b从左到右找到它们的第一个不同位置 i如果 a[i] b[i]则认为 a 的字典序小于 b。因此总波动值为 1 1 1 3。1 n 100000。-10000000000 target 10000000000。输入 n 3, target 0。输出 [-3,1,2]。解释和为 0 且绝对值组成大小为 3 的排列的数组有[-3, 1, 2][-3, 2, 1][-2, -1, 3][-2, 3, -1][-1, -2, 3][-1, 3, -2][1, -3, 2][1, 2, -3][2, -3, 1][2, 1, -3][3, -2, -1][3, -1, -2]字典序最小的是 [-3, 1, 2]。题目来自力扣3752。分步详细过程我们以n3target0为例完整拆解解题的每一步逻辑全程不写代码只讲原理和操作。第一步判断是否存在合法数组首先要确定有没有满足条件的数组这是解题的前提核心分3个小步骤计算1~n的总和最大值1到n所有数相加的总和是固定值公式总和 n*(n1)/2n3时1236这个值是所有元素全为正数时的总和记为mx。判断target的数值范围是否合法数组元素是1~n加正负号所以总和的最大值是mx全正最小值是-mx全负。如果target mx 或者 target -mx直接判定无合法数组。n3target00在-6和6之间范围合法。判断奇偶性是否匹配我们把一个正数x改成负数-x总和的变化是减少了2x总和 原总和 - 2x。这意味着原总和 - 目标值必须是偶数因为是2的倍数否则无法通过改符号得到target。公式(mx - target) % 2 0 才合法。n3mx6target06-066是偶数奇偶性合法。✅ 三个条件都满足存在合法数组任意一个不满足直接返回空数组。第二步计算需要取负号的数字总和这是核心计算步骤目的是找到哪些数字需要加负号设需要取负号的数字的绝对值之和为negS推导公式negS (mx - target) / 2原理原总和mx每把一个数x变负总和减2x总共需要减mx-target所以总负号数的和就是这个值的一半。代入计算n3mx6target0 → negS(6-0)/23。结论我们需要从1、2、3中选若干个数让它们的和等于3这些数最终要变成负数。第三步确定哪些数字取负号保证字典序最小字典序最小的规则左边的数字尽可能小优先用大负数右边的数字尽可能大。因为负数 正数所以要让数组字典序最小必须左边优先放绝对值大的负数。操作规则从最大的数字开始依次尝试取负直到选中的数字总和等于negS从n3开始检查3 ≤ 3negS选中3取负剩余需要的和3-30剩余需要的和为0剩下的数字2、1都不取负保持正数最终确定只有数字3需要取负1和2保持正数。第四步构造字典序最小的数组按照「左边放负数右边放正数负数从大到小排正数从小到大排」的规则填充数组数组长度为3左指针从开头开始右指针从末尾开始先把确定的负数-3放在最左侧满足字典序最小剩下的正数1、2按从小到大的顺序依次放在负数后面最终数组[-3, 1, 2]和题目要求的输出完全一致。时间复杂度与额外空间复杂度分析1. 总时间复杂度整个过程只做了一次从n到1的循环遍历没有嵌套循环也没有额外的递归/复杂操作。循环次数等于n的值因此时间复杂度为O(n)。n最大为100000O(n)的效率完全满足题目要求2. 总额外空间复杂度我们只创建了一个结果数组存储最终答案没有使用其他额外的数据结构如栈、队列、哈希表等也没有递归调用栈。结果数组的长度等于n因此额外空间复杂度为O(n)。如果不算结果数组的必要空间额外辅助空间为O(1)总结解题分四大核心步骤合法性判断 → 计算负号数字总和 → 选定负号数字 → 构造最小字典序数组时间复杂度O(n)线性遍历一次额外空间复杂度O(n)仅存储结果数组。Go完整代码如下packagemainimport(fmt)funclexSmallestNegatedPerm(nint,targetint64)[]int{t:int(target)mx:n*(n1)/2iftmx||-tmx||(mx-t)%2!0{returnnil}negS:(mx-t)/2// 取负号的元素的绝对值之和ans:make([]int,n)l,r:0,n-1// 从 1,2,...,n 中选一些数元素和等于 negS// 为了让负数部分的字典序尽量小从大往小选forx:n;x0;x--{ifnegSx{negS-x ans[l]-x l}else{// 大的正数填在末尾ans[r]x r--}}returnans}funcmain(){n:3target:int64(0)result:lexSmallestNegatedPerm(n,target)fmt.Println(result)}Python完整代码如下# -*-coding:utf-8-*-fromtypingimportList,OptionaldeflexSmallestNegatedPerm(n:int,target:int)-Optional[List[int]]:ttarget mxn*(n1)//2iftmxor-tmxor(mx-t)%2!0:returnNonenegS(mx-t)//2# 取负号的元素的绝对值之和ans[0]*n l,r0,n-1# 从 1,2,...,n 中选一些数元素和等于 negS# 为了让负数部分的字典序尽量小从大往小选forxinrange(n,0,-1):ifnegSx:negS-x ans[l]-x l1else:# 大的正数填在末尾ans[r]x r-1returnansdefmain():n3target0resultlexSmallestNegatedPerm(n,target)print(result)if__name____main__:main()C完整代码如下#includeiostream#includevectorstd::vectorint*lexSmallestNegatedPerm(intn,longlongtarget){inttstatic_castint(target);intmxn*(n1)/2;if(tmx||-tmx||(mx-t)%2!0){returnnullptr;}intnegS(mx-t)/2;// 取负号的元素的绝对值之和std::vectorint*ansnewstd::vectorint(n);intl0,rn-1;// 从 1,2,...,n 中选一些数元素和等于 negS// 为了让负数部分的字典序尽量小从大往小选for(intxn;x0;x--){if(negSx){negS-x;(*ans)[l]-x;l;}else{// 大的正数填在末尾(*ans)[r]x;r--;}}returnans;}intmain(){intn3;longlongtarget0;std::vectorint*resultlexSmallestNegatedPerm(n,target);if(result!nullptr){std::cout[;for(size_t i0;iresult-size();i){std::cout(*result)[i];if(iresult-size()-1)std::cout ;}std::cout]std::endl;deleteresult;// 记得释放内存}else{std::coutnilstd::endl;}return0;}

更多文章