小红的数组权值
[题目链接](https://www.nowcoder.com/practice/383eb5dc6e8044f9b879f1848a6784e8)
思路
问题分析
给定数组 ,需要把数字
全部插入数组的任意位置,使得插入后相邻元素差的绝对值之和(即数组权值)最小。原数组的相对顺序保持不变。
关键观察:在某个间隙中插入数不会减少贡献
设原数组中有一对相邻元素 ,它们对权值的贡献是
。如果在它们之间插入一个值
,贡献变成
。由三角不等式,
,当且仅当
在
和
之间(含端点)时取等。
因此,如果插入的值在该间隙覆盖的范围 内,贡献不变;否则贡献增大。
哪些值可以"免费"插入?
考虑所有相邻间隙覆盖的值域范围的并集。由于数组中的值构成一条"路径",从某个值走到另一个值,所有介于 与
之间的整数都能在某个间隙中找到覆盖——对它们来说,插入代价为零。
因此,只有超出原数组值域范围的数才会产生额外代价:
- 若
,则
需要额外处理。
- 若
,则
需要额外处理。
最优插入越界值
以高于上界的值 为例(低于下界的情况完全对称)。这些值是连续的一段,我们需要把它们一起插入到数组的某个位置(某个间隙、数组头部或尾部)。
插入到相邻元素 之间时,最优是走"一头一尾"的路线,有两种走法:
$$
$$
额外代价为 。
插入在数组头部或尾部时,额外代价为:
$$
其中 是头部/尾部元素。
遍历所有 个间隙加头尾两个位置,取最小额外代价即可。
最终答案
$$
复杂度
- 时间复杂度:
,一次遍历计算原始权值,再各一次遍历处理低值和高值。
- 空间复杂度:
,只用常数额外空间。
代码
class Solution {
public:
long long min_value(vector<int>& nums, int m) {
int n = nums.size();
long long weight = 0;
int mn = nums[0], mx = nums[0];
for (int i = 0; i < n; i++) {
mn = min(mn, nums[i]);
mx = max(mx, nums[i]);
if (i > 0) weight += abs(nums[i] - nums[i - 1]);
}
// 处理低于下界的值 1..mn-1
long long lowExtra = 0;
if (mn > 1) {
int L = 1, R = mn - 1, span = R - L;
long long best = (long long)span + min(abs(nums[0] - L), abs(nums[0] - R));
best = min(best, (long long)span + min(abs(nums[n - 1] - L), abs(nums[n - 1] - R)));
for (int i = 0; i < n - 1; i++) {
long long orig = abs(nums[i] - nums[i + 1]);
long long c1 = (long long)abs(nums[i] - L) + span + abs(R - nums[i + 1]);
long long c2 = (long long)abs(nums[i] - R) + span + abs(L - nums[i + 1]);
best = min(best, min(c1, c2) - orig);
}
lowExtra = best;
}
// 处理高于上界的值 mx+1..m
long long highExtra = 0;
if (m > mx) {
int L = mx + 1, R = m, span = R - L;
long long best = (long long)span + min(abs(nums[0] - L), abs(nums[0] - R));
best = min(best, (long long)span + min(abs(nums[n - 1] - L), abs(nums[n - 1] - R)));
for (int i = 0; i < n - 1; i++) {
long long orig = abs(nums[i] - nums[i + 1]);
long long c1 = (long long)abs(nums[i] - L) + span + abs(R - nums[i + 1]);
long long c2 = (long long)abs(nums[i] - R) + span + abs(L - nums[i + 1]);
best = min(best, min(c1, c2) - orig);
}
highExtra = best;
}
return weight + lowExtra + highExtra;
}
};
import java.util.*;
public class Solution {
public long min_value(int[] nums, int m) {
int n = nums.length;
long weight = 0;
int mn = nums[0], mx = nums[0];
for (int i = 0; i < n; i++) {
mn = Math.min(mn, nums[i]);
mx = Math.max(mx, nums[i]);
if (i > 0) weight += Math.abs(nums[i] - nums[i - 1]);
}
long lowExtra = 0;
if (mn > 1) {
int L = 1, R = mn - 1, span = R - L;
long best = (long) span + Math.min(Math.abs(nums[0] - L), Math.abs(nums[0] - R));
best = Math.min(best, (long) span + Math.min(Math.abs(nums[n - 1] - L), Math.abs(nums[n - 1] - R)));
for (int i = 0; i < n - 1; i++) {
long orig = Math.abs(nums[i] - nums[i + 1]);
long c1 = (long) Math.abs(nums[i] - L) + span + Math.abs(R - nums[i + 1]);
long c2 = (long) Math.abs(nums[i] - R) + span + Math.abs(L - nums[i + 1]);
best = Math.min(best, Math.min(c1, c2) - orig);
}
lowExtra = best;
}
long highExtra = 0;
if (m > mx) {
int L = mx + 1, R = m, span = R - L;
long best = (long) span + Math.min(Math.abs(nums[0] - L), Math.abs(nums[0] - R));
best = Math.min(best, (long) span + Math.min(Math.abs(nums[n - 1] - L), Math.abs(nums[n - 1] - R)));
for (int i = 0; i < n - 1; i++) {
long orig = Math.abs(nums[i] - nums[i + 1]);
long c1 = (long) Math.abs(nums[i] - L) + span + Math.abs(R - nums[i + 1]);
long c2 = (long) Math.abs(nums[i] - R) + span + Math.abs(L - nums[i + 1]);
best = Math.min(best, Math.min(c1, c2) - orig);
}
highExtra = best;
}
return weight + lowExtra + highExtra;
}
}
class Solution:
def min_value(self, nums: list, m: int) -> int:
n = len(nums)
weight = sum(abs(nums[i + 1] - nums[i]) for i in range(n - 1))
mn, mx = min(nums), max(nums)
low_extra = 0
if mn > 1:
L, R = 1, mn - 1
span = R - L
best = span + min(abs(nums[0] - L), abs(nums[0] - R))
best = min(best, span + min(abs(nums[-1] - L), abs(nums[-1] - R)))
for i in range(n - 1):
orig = abs(nums[i] - nums[i + 1])
c1 = abs(nums[i] - L) + span + abs(R - nums[i + 1])
c2 = abs(nums[i] - R) + span + abs(L - nums[i + 1])
best = min(best, min(c1, c2) - orig)
low_extra = best
high_extra = 0
if m > mx:
L, R = mx + 1, m
span = R - L
best = span + min(abs(nums[0] - L), abs(nums[0] - R))
best = min(best, span + min(abs(nums[-1] - L), abs(nums[-1] - R)))
for i in range(n - 1):
orig = abs(nums[i] - nums[i + 1])
c1 = abs(nums[i] - L) + span + abs(R - nums[i + 1])
c2 = abs(nums[i] - R) + span + abs(L - nums[i + 1])
best = min(best, min(c1, c2) - orig)
high_extra = best
return weight + low_extra + high_extra
function min_value(nums, m) {
const n = nums.length;
let weight = 0;
let mn = nums[0], mx = nums[0];
for (let i = 0; i < n; i++) {
mn = Math.min(mn, nums[i]);
mx = Math.max(mx, nums[i]);
if (i > 0) weight += Math.abs(nums[i] - nums[i - 1]);
}
let lowExtra = 0;
if (mn > 1) {
const L = 1, R = mn - 1, span = R - L;
let best = span + Math.min(Math.abs(nums[0] - L), Math.abs(nums[0] - R));
best = Math.min(best, span + Math.min(Math.abs(nums[n - 1] - L), Math.abs(nums[n - 1] - R)));
for (let i = 0; i < n - 1; i++) {
const orig = Math.abs(nums[i] - nums[i + 1]);
const c1 = Math.abs(nums[i] - L) + span + Math.abs(R - nums[i + 1]);
const c2 = Math.abs(nums[i] - R) + span + Math.abs(L - nums[i + 1]);
best = Math.min(best, Math.min(c1, c2) - orig);
}
lowExtra = best;
}
let highExtra = 0;
if (m > mx) {
const L = mx + 1, R = m, span = R - L;
let best = span + Math.min(Math.abs(nums[0] - L), Math.abs(nums[0] - R));
best = Math.min(best, span + Math.min(Math.abs(nums[n - 1] - L), Math.abs(nums[n - 1] - R)));
for (let i = 0; i < n - 1; i++) {
const orig = Math.abs(nums[i] - nums[i + 1]);
const c1 = Math.abs(nums[i] - L) + span + Math.abs(R - nums[i + 1]);
const c2 = Math.abs(nums[i] - R) + span + Math.abs(L - nums[i + 1]);
best = Math.min(best, Math.min(c1, c2) - orig);
}
highExtra = best;
}
return weight + lowExtra + highExtra;
}
module.exports = { min_value };

京公网安备 11010502036488号