leetcode —— 2602 使数组元素全部相等的最少操作次数

题目

给你一个正整数数组 nums 。

同时给你一个长度为 m 的整数数组 queries 。第 i 个查询中,你需要将 nums 中所有元素变成 queries[i] 。你可以执行以下操作 任意 次:将数组里一个元素 增大 或者 减小 1 。

请你返回一个长度为 m 的数组 answer ,其中 answer[i]是将 nums 中所有元素变成 queries[i] 的 最少 操作次数。

注意,每次查询后,数组变回最开始的值。

示例 1:

输入:nums = [3,1,6,8], queries = [1,5]
输出:[14,10]
解释:第一个查询,我们可以执行以下操作:
- 将 nums[0] 减小 2 次,nums = [1,1,6,8] 。
- 将 nums[2] 减小 5 次,nums = [1,1,1,8] 。
- 将 nums[3] 减小 7 次,nums = [1,1,1,1] 。
第一个查询的总操作次数为 2 + 5 + 7 = 14 。
第二个查询,我们可以执行以下操作:
- 将 nums[0] 增大 2 次,nums = [5,1,6,8] 。
- 将 nums[1] 增大 4 次,nums = [5,5,6,8] 。
- 将 nums[2] 减小 1 次,nums = [5,5,5,8] 。
- 将 nums[3] 减小 3 次,nums = [5,5,5,5] 。
第二个查询的总操作次数为 2 + 4 + 1 + 3 = 10 。

思想:

二分查找+ 前缀和

代码:

class Solution {
    public List<Long> minOperations(int[] nums, int[] queries) {
        // 先给数组排序
        Arrays.sort(nums);
        int n = nums.length;

        // 定义前缀和数组
        long[] preSum = new long[n+1];

        
        // 遍历数组 计算数组前缀和
        for(int i = 0; i < n; i++){
            preSum[i + 1] = preSum[i] + nums[i];
        }

        // 用于存储每个查询的结果 queries数组中有几个值就返回几个结果
        ArrayList<Long> ans = new ArrayList<>(queries.length);
        // 遍历查询数组
        for(int q : queries){
            // 使用二分查找找到nums中第一个大于等于q 的索引
            int j = lowerBound(nums,q);
            // 将nums中所有小于q的值变为q 需要操作的次数
            long left = (long) q * j - preSum[j];
           

            // 计算大于q的所有元素变为q所需要的操作次数
            long right = preSum[n] - preSum[j] - (long) q * (n-j);
            ans.add(left + right);
        }
        return ans;

    }
    // 用于找到数组中第一个大于或等于target的第一个元素的索引
    public int lowerBound(int[] nums, int target){
        int left = -1;
        int right = nums.length;
        while(left+1 < right){
            int mid = left + (right - left) /2;
            if(nums[mid] < target){
                left = mid + 1;
            }else{
                right = mid -1;
            }
        }
        return right;
    }
}

上一篇:springboot275毕业就业信息管理系统的设计与实现


下一篇:OpenCV 图像处理库功能模块介绍