
2026-02-25:分割数组得到最小绝对差。用go语言,给定一个整数数组 nums,把它切成两个非空的连续区间——记作 left 和 right。要求 left 中的元素单调上升(每个数都大于它前面的那个数),right 中的元素单调下降(每个数都小于它前面的那个数)。目标是使这两段的元素和之差的绝对值尽可能小,并返回这个最小的绝对差值;如果不存在满足单调性要求的分割方式,则返回 -1。 说明:这里的“子数组”指数组中的连续且非空的一段。
2 <= nums.length <= 100000。
1 <= nums[i] <= 100000。
输入: nums = [1,3,2]。
输出: 2。
解释:
i | left | right | 是否有效 | left 和 right 和 | 绝对差值 |
|---|---|---|---|---|---|
0 | [1] | [3, 2] | 是 | 1,5 | |
1 | [1, 3] | [2] | 是 | 4,2 |
因此,最小绝对差值为 2。
题目来自力扣3698。
我们以输入 nums = [1, 3, 2] 为例,逐步拆解代码的执行逻辑,核心目标是找到满足“左段严格递增、右段严格递减”的分割方式,并计算最小绝对差值。
首先明确两个关键区间的定义:
left 是严格递增的前缀、right 是严格递减的后缀,且两者都非空。代码首先遍历数组,找到最长的严格递增前缀,并累加其元素和:
pre = nums[0] = 1,i = 1(从第二个元素开始检查);i=1,nums[1]=3 > nums[0]=1,满足严格递增 → pre += 3(pre变为4),i++(i变为2);i=2,nums[2]=2,需要和 nums[1]=3 比较 → 2 > 3 不成立,循环终止;[1,3],和为4,i=2(表示前缀结束在索引1,下一个索引是2)。接着从数组末尾遍历,找到最长的严格递减后缀,并累加其元素和:
suf = nums[2] = 2,j = 1(从倒数第二个元素开始检查);j=1,nums[1]=3 > nums[2]=2,满足严格递减 → suf += 3(suf变为5),j--(j变为0);j=0,nums[0]=1,需要和 nums[1]=3 比较 → 1 > 3 不成立,循环终止;[3,2],和为5,j=0(表示后缀开始在索引1,上一个索引是0)。代码通过 i <= j 判断是否存在有效分割:
i=2,j=0 → 2 <= 0 不成立,说明存在有效分割,进入后续计算;i <= j(比如数组是 [1,2,4,3,5],递增前缀到索引2,递减后缀从索引3开始,中间有重叠),说明没有任何分割点能同时满足左段递增、右段递减,直接返回-1。首先计算 d = pre - suf = 4 - 5 = -1,然后根据 i 和 j 的关系分情况计算最小绝对差:
情况二的条件是 i-1 == j(即递增前缀的最后一个索引 = 递减后缀的第一个索引):
i-1 = 1,j=0 → 1 == 0 不成立,跳过情况二;[1,4,3],i=2,j=1 → i-1=1=j),说明分割点唯一,直接返回 abs(d) 即可。情况三是核心,本质是:递增前缀和递减后缀共享了一个元素(本例中是 nums[1]=3),需要修正这个重复计算的问题:
suf 中包含了 nums[i-1]=3,pre 中也包含了 nums[i-1]=3,因此需要调整差值:nums[i-1] 归给left → 相当于 d - nums[i-1](即 -1 - 3 = -4),绝对值是4;nums[i-1] 归给right → 相当于 d + nums[i-1](即 -1 + 3 = 2),绝对值是2;min(4, 2) = 2,这就是最终的最小绝对差值。代码将最小值转为 int64 类型返回,main函数打印结果为2,符合题目要求。
n 个元素(n为数组长度),时间复杂度O(n);n 个元素,时间复杂度O(n);pre、suf、i、j、d 等都是单个整型变量,空间开销为O(1);nums 切片,没有额外创建新的数组/切片;abs 和 min 仅使用临时变量,无额外空间开销;.
package main
import (
"fmt"
)
func splitArray(nums []int)int64 {
n := len(nums)
// 最长严格递增前缀
pre := nums[0]
i := 1
for i < n && nums[i] > nums[i-1] {
pre += nums[i]
i++
}
// 最长严格递减后缀
suf := nums[n-1]
j := n - 2
for j >= 0 && nums[j] > nums[j+1] {
suf += nums[j]
j--
}
// 情况一
if i <= j {
return-1
}
d := pre - suf
// 情况二
if i-1 == j {
returnint64(abs(d))
}
// 情况三,suf 多算了一个 nums[i-1],或者 pre 多算了一个 nums[i-1]
returnint64(min(abs(d+nums[i-1]), abs(d-nums[i-1])))
}
func abs(x int)int {
if x < 0 {
return -x
}
return x
}
func main() {
nums := []int{1, 3, 2}
result := splitArray(nums)
fmt.Println(result)
}

.
# -*-coding:utf-8-*-
def split_array(nums):
n = len(nums)
# 最长严格递增前缀
pre = nums[0]
i = 1
while i < n and nums[i] > nums[i-1]:
pre += nums[i]
i += 1
# 最长严格递减后缀
suf = nums[n-1]
j = n - 2
while j >= 0 and nums[j] > nums[j+1]:
suf += nums[j]
j -= 1
# 情况一:前缀和后缀重叠或有间隙
if i <= j:
return-1
d = pre - suf
# 情况二:前缀和后缀刚好相邻
if i - 1 == j:
return abs(d)
# 情况三:前缀和后缀重叠了一个元素(nums[i-1])
# 需要计算两种情况的最小值
return min(abs(d + nums[i-1]), abs(d - nums[i-1]))
def main():
nums = [1, 3, 2]
result = split_array(nums)
print(result)
if __name__ == "__main__":
main()
.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
long long splitArray(vector<int>& nums) {
int n = nums.size();
// 最长严格递增前缀
long long pre = nums[0];
int i = 1;
while (i < n && nums[i] > nums[i-1]) {
pre += nums[i];
i++;
}
// 最长严格递减后缀
long long suf = nums[n-1];
int j = n - 2;
while (j >= 0 && nums[j] > nums[j+1]) {
suf += nums[j];
j--;
}
// 情况一:前缀和后缀重叠或有间隙
if (i <= j) {
return-1;
}
long long d = pre - suf;
// 情况二:前缀和后缀刚好相邻
if (i - 1 == j) {
return abs(d);
}
// 情况三:前缀和后缀重叠了一个元素(nums[i-1])
// 需要计算两种情况的最小值
return min(abs(d + nums[i-1]), abs(d - nums[i-1]));
}
int main() {
vector<int> nums = {1, 3, 2};
long long result = splitArray(nums);
cout << result << endl;
return0;
}

·
我们相信人工智能为普通人提供了一种“增强工具”,并致力于分享全方位的AI知识。在这里,您可以找到最新的AI科普文章、工具评测、提升效率的秘籍以及行业洞察。 欢迎关注“福大大架构师每日一题”,发消息可获得面试资料,让AI助力您的未来发展。
·