LeetCode 1674. 使数组互补的最少操作次数

1674. 使数组互补的最少操作次数

给你一个长度为 偶数 n 的整数数组 nums 和一个整数 limit 。每一次操作,你可以将 nums 中的任何整数替换为 1 到 limit 之间的另一个整数。

如果对于所有下标 i下标从 0 开始),nums[i] + nums[n - 1 - i] 都等于同一个数,则数组 nums 是 互补的 。例如,数组 [1,2,3,4] 是互补的,因为对于所有下标 i ,nums[i] + nums[n - 1 - i] = 5 。

返回使数组 互补 的 最少 操作次数。

示例 1:

输入:nums = [1,2,4,3], limit = 4
输出:1
解释:经过 1 次操作,你可以将数组 nums 变成 [1,2,2,3](加粗元素是变更的数字):
nums[0] + nums[3] = 1 + 3 = 4.
nums[1] + nums[2] = 2 + 2 = 4.
nums[2] + nums[1] = 2 + 2 = 4.
nums[3] + nums[0] = 3 + 1 = 4.
对于每个 i ,nums[i] + nums[n-1-i] = 4 ,所以 nums 是互补的。

示例 2:

输入:nums = [1,2,2,1], limit = 2
输出:2
解释:经过 2 次操作,你可以将数组 nums 变成 [2,2,2,2] 。你不能将任何数字变更为 3 ,因为 3 > limit 。

示例 3:

输入:nums = [1,2,1,2], limit = 2
输出:0
解释:nums 已经是互补的。

提示:

  • n == nums.length
  • 2 <= n <= 10^5
  • 1 <= nums[i] <= limit <= 10^5
  • n 是偶数。

提示 1

Given a target sum x, each pair of nums[i] and nums[n-1-i] would either need 0, 1, or 2 modifications.


提示 2

Can you find the optimal target sum x value such that the sum of modifications is minimized?


提示 3

Create a difference array to efficiently sum all the modifications.

解法1:差分数组

提示 1
给定目标总和 x,nums[i] 和 nums[n-1-i] 的每一对需要修改 0、1 或 2 次。
提示 2
你能找到使修改次数最小的最优目标总和 x 值吗?
提示 3
创建一个差值数组来有效地求和所有修改。

对于每对元素(a, b),最多2次操作,就可以变成所有可能变成的和了。因此一共有3种情况:

  • 0次操作只能达成原本的和。[a+b]
  • 1次操作的下限为:将较大值变为1,加上较小值的和;上限为:将较小值变为limit,加上较大值的和。[1 + min(a, b), limit + max(a, b)]
  • 2次操作的下限为2,上限为limit * 2。[2, limit * 2]

2 <= 1 + min(a,b) <= a + b <= limit + max(a, b) <= limit * 2

  • [2, 1 + min(a,b) ) 最少需要 2 次操作,
  • [1 + min(a, b), a + b) 最少需要 1 次操作,
  • [a + b] 最少需要 0 次操作,
  • (a + b, limit + max(a, b)] 最少需要 1 次操作,
  • (limit + max(a, b), limit * 2]最少需要 2 次操作。

我们将每对元素达到某个和需要的最少操作数加在一起,就是总的最少操作数,因此这题相当于区间相加问题,可以用差分数组解决。

Java版:

class Solution {
    public int minMoves(int[] nums, int limit) {
        int n = nums.length;
        int[] diff = new int[2 * limit + 2];
        for (int i = 0; i + i < n; i++) {
            int a = nums[i];
            int b = nums[n - 1 - i];
            // 2 <= 1 + min(a,b) <= a + b <= limit + max(a, b) <= limit * 2
            diff[2] += 2;
            diff[1 + Math.min(a, b)] -= 1;
            diff[a + b] -= 1;
            diff[a + b + 1] += 1;
            diff[limit + Math.max(a, b) + 1] += 1;
        }
        int ans = Integer.MAX_VALUE;
        for (int i = 2; i <= 2 * limit; i++) {
            diff[i] += diff[i - 1];
            ans = Math.min(diff[i], ans);
        }
        return ans;
    }
}

Python3版:

class Solution:
    def minMoves(self, nums: List[int], limit: int) -> int:
        n = len(nums)
        diff = [0] * (limit * 2 + 2)
        for i in range(n // 2):
            a = nums[i]
            b = nums[n - 1 - i]
            # 2 < 1 + min(a, b) < a + b < limit + max(a, b) < limit * 2
            diff[2] += 2
            diff[1 + min(a, b)] -= 1
            diff[a + b] -= 1
            diff[a + b + 1] += 1
            diff[limit + max(a, b) + 1] += 1
        
        ans = inf 
        for i in range(2, limit * 2 + 1):
            diff[i] += diff[i - 1]
            ans = min(ans, diff[i])
        return ans

复杂度分析

  • 时间复杂度:O(n),n 为数组 nums 的长度。
  • 空间复杂度:O(limit),limit 为输入值。
  • 13
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值