中位数贪心

(leetcode3086)-------------------Java实现

题目表述

给你一个下标从 0 开始的二进制数组 nums,其长度为 n ;另给你一个 正整数 k 以及一个 非负整数 maxChanges 。

灵茶山艾府在玩一个游戏,游戏的目标是让灵茶山艾府使用 最少 数量的 行动 次数从 nums 中拾起 k 个 1 。游戏开始时,灵茶山艾府可以选择数组 [0, n - 1] 范围内的任何索引index 站立。如果 nums[index] == 1 ,灵茶山艾府就会拾起一个 1 ,并且 nums[index] 变成0(这 不算 作一次行动)。之后,灵茶山艾府可以执行 任意数量 的 行动(包括零次),在每次行动中灵茶山艾府必须 恰好 执行以下动作之一:

选择任意一个下标 j != index 且满足 nums[j] == 0 ,然后将 nums[j] 设置为 1 。这个动作最多可以执行 maxChanges 次。
选择任意两个相邻的下标 x 和 y(|x - y| == 1)且满足 nums[x] == 1, nums[y] == 0 ,然后交换它们的值(将 nums[y] = 1 和 nums[x] = 0)。如果 y == index,在这次行动后灵茶山艾府拾起一个 1 ,并且 nums[y] 变成 0 。
返回灵茶山艾府拾起 恰好 k 个 1 所需的 最少 行动次数。

样例

示例 1:

输入:nums = [1,1,0,0,0,1,1,0,0,1], k = 3, maxChanges = 1

输出:3

解释:如果游戏开始时灵茶山艾府在 index == 1 的位置上,按照以下步骤执行每个动作,他可以利用 3 次行动拾取 3 个 1 :

游戏开始时灵茶山艾府拾取了一个 1 ,nums[1] 变成了 0。此时 nums 变为 [1,0,0,0,0,1,1,0,0,1] 。
选择 j == 2 并执行第一种类型的动作。nums 变为 [1,0,1,0,0,1,1,0,0,1]
选择 x == 2 和 y == 1 ,并执行第二种类型的动作。nums 变为 [1,1,0,0,0,1,1,0,0,1] 。由于 y == index,灵茶山艾府拾取了一个 1 ,nums 变为 [1,0,0,0,0,1,1,0,0,1] 。
选择 x == 0 和 y == 1 ,并执行第二种类型的动作。nums 变为 [0,1,0,0,0,1,1,0,0,1] 。由于 y == index,灵茶山艾府拾取了一个 1 ,nums 变为 [0,0,0,0,0,1,1,0,0,1] 。
请注意,灵茶山艾府也可能执行其他的 3 次行动序列达成拾取 3 个 1 。

示例 2:

输入:nums = [0,0,0,0], k = 2, maxChanges = 3

输出:4

解释:如果游戏开始时灵茶山艾府在 index == 0 的位置上,按照以下步骤执行每个动作,他可以利用 4 次行动拾取 2 个 1 :

选择 j == 1 并执行第一种类型的动作。nums 变为 [0,1,0,0] 。
选择 x == 1 和 y == 0 ,并执行第二种类型的动作。nums 变为 [1,0,0,0] 。由于 y == index,灵茶山艾府拾起了一个 1 ,nums 变为 [0,0,0,0] 。
再次选择 j == 1 并执行第一种类型的动作。nums 变为 [0,1,0,0] 。
再次选择 x == 1 和 y == 0 ,并执行第二种类型的动作。nums 变为 [1,0,0,0] 。由于y == index,灵茶山艾府拾起了一个 1 ,nums 变为 [0,0,0,0] 。

条件

2 <= n <= 105
0 <= nums[i] <= 1
1 <= k <= 105
0 <= maxChanges <= 105
maxChanges + sum(nums) >= k

思路

中位数贪心+前缀和滑动窗口

注意点

1、注意前缀和数组计算细节(分两部分计算)
2、注意中位数贪心细节,[0,4) 中 所有数到1和到2的距离是相同的。(1,2的中间部分重合,两边部分都是相加)。

ac代码

Java:
class Solution {
    public long minimumMoves(int[] nums, int k, int maxChanges) {
        int c = 0;
        List<Integer> sit = new ArrayList<>();
        for(int i=0;i<nums.length;i++){
            if (nums[i]!=1)
                continue;
            c = Math.max(1,c);
            sit.add(i);
            if (i-1>=0&&nums[i-1]==1||i+1<nums.length&&nums[i+1]==1)
            {
                if (i-1>=0&&nums[i-1]==1&&i+1<nums.length&&nums[i+1]==1)
                c =3;
                    
                c=  Math.max(2,c);
            }
        }
        // System.out.println(c);
        if ((maxChanges+c)>=k)
        {
            if (c==3) {
                if (k <= 1)
                    return 0;
                if (k <= 3)
                    return k - 1;
                return (k-3)* 2L +c-1;
            }
            if (c==2){
                if (k<=1)
                    return 0;
                if (k<=2)
                    return k-1;
                return (k-2)* 2L +c-1;
            }
            if (c==1)
            {
                if (k<=1)
                    return 0;
                return (k-1) * 2L;
            }
            return k*2L;
        }
        long[] sum = new long[sit.size()+1];
        for (int i = 0; i < sit.size(); i++) {
            sum[i + 1] = sum[i] + sit.get(i);
        }

        long result = Long.MAX_VALUE;
        int time = k-maxChanges;
        for (int right = time;right<=sit.size();right++){
            int left = right-time;
            int middle = left+time/2;
            long now = sit.get(middle);
            long s1 = now*(middle-left)-sum[middle]+sum[left];
            long s2 = sum[right]-sum[middle]-now*(right-middle);
            System.out.println(s1+s2);
            result = Math.min(result,s1+s2);
        }
        return result+maxChanges* 2L;
    }
}

(leetcode2968)-------------------Java实现

题目表述

给你一个下标从 0 开始的整数数组 nums 和一个整数 k 。

你可以对数组执行 至多 k 次操作:

从数组中选择一个下标 i ,将 nums[i] 增加 或者 减少 1 。
最终数组的频率分数定义为数组中众数的 频率 。

请你返回你可以得到的 最大 频率分数。

众数指的是数组中出现次数最多的数。一个元素的频率指的是数组中这个元素的出现次数。

样例

示例 1:

输入:nums = [1,2,6,4], k = 3
输出:3
解释:我们可以对数组执行以下操作:

  • 选择 i = 0 ,将 nums[0] 增加 1 。得到数组 [2,2,6,4] 。
  • 选择 i = 3 ,将 nums[3] 减少 1 ,得到数组 [2,2,6,3] 。
  • 选择 i = 3 ,将 nums[3] 减少 1 ,得到数组 [2,2,6,2] 。
    元素 2 是最终数组中的众数,出现了 3 次,所以频率分数为 3 。
    3 是所有可行方案里的最大频率分数。
    示例 2:

输入:nums = [1,4,4,2,4], k = 0
输出:3
解释:我们无法执行任何操作,所以得到的频率分数是原数组中众数的频率 3 。

条件

1 <= nums.length <= 105
1 <= nums[i] <= 109
0 <= k <= 1014

思路

中位数贪心+前缀和滑动窗口

注意点

1、注意前缀和数组计算细节(分两部分计算)
2、注意中位数贪心细节,[0,4) 中 所有数到1和到2的距离是相同的。(1,2的中间部分重合,两边部分都是相加)。

ac代码

Java:
class Solution {
    public int maxFrequencyScore(int[] nums, long k) {
        int n  = nums.length;
        Arrays.sort(nums);
        long[] sum = new long[n+1];
        for (int i = 0; i < n; i++) {
            sum[i+1] = sum[i]+nums[i];
        }
        int left = 0;
        int ans = 0;
        for (int i=0;i<n;i++){
            long now_change = Long.MAX_VALUE;
            while (now_change>k){
                int middle = left+(i-left)/2;
                long s1 = (middle-left)*(long)nums[middle]-sum[middle]+sum[left];
                long s2 = sum[i+1]-sum[middle+1] - (i-middle)*(long)nums[middle];
                now_change = Math.min(now_change,s1+s2);
                if (now_change>k)
                    left++;
            }
            ans = Math.max(ans,i-left+1);

        }
        return ans;
    }
}

你可能感兴趣的:(算法,python,数据结构)