最大化最小值 - 二分

62 阅读3分钟

题单: leetcode.cn/problems/mi…

2616. Minimize the Maximum Difference of Pairs

You are given a 0-indexed integer array nums and an integer p. Find p pairs of indices of nums such that the maximum difference amongst all the pairs is minimized. Also, ensure no index appears more than once amongst the p pairs.

Note that for a pair of elements at the index i and j, the difference of this pair is |nums[i] - nums[j]|, where |x| represents the absolute value of x.

Return the minimum maximum difference among all p pairs.  We define the maximum of an empty set to be zero.

 

Example 1:

Input: nums = [10,1,2,7,1,3], p = 2
Output: 1
Explanation: The first pair is formed from the indices 1 and 4, and the second pair is formed from the indices 2 and 5. 
The maximum difference is max(|nums[1] - nums[4]|, |nums[2] - nums[5]|) = max(0, 1) = 1. Therefore, we return 1.

Example 2:

Input: nums = [4,2,1,2], p = 1
Output: 0
Explanation: Let the indices 1 and 3 form a pair. The difference of that pair is |2 - 2| = 0, which is the minimum we can attain.

注意:二分分的是difference of each pair

class Solution {
    public int minimizeMax(int[] nums, int p) {
        Arrays.sort(nums);
        int len = nums.length;
        int left = -1;
        int right = nums[len-1] - nums[0];

        while(left + 1 < right) {
            int mid = left + (right - left) / 2;
            int cnt = 0;
            for(int i = 1; i < nums.length; i++) {
                if(nums[i] - nums[i-1] <= mid) {
                    cnt++;
                    i++;
                }
            }
            if(cnt < p) {
                left = mid;
            } else {
                right = mid;
            }
        }
        return right;
    }
}

2439. Minimize Maximum of Array

You are given a 0-indexed array nums comprising of n non-negative integers.

In one operation, you must:

  • Choose an integer i such that 1 <= i < n and nums[i] > 0.
  • Decrease nums[i] by 1.
  • Increase nums[i - 1] by 1.

Return the minimum possible value of the maximum integer of nums after performing any number of operations.

 

Example 1:

Input: nums = [3,7,1,6]
Output: 5
Explanation:
One set of optimal operations is as follows:
1. Choose i = 1, and nums becomes [4,6,1,6].
2. Choose i = 3, and nums becomes [4,6,2,5].
3. Choose i = 1, and nums becomes [5,5,2,5].
The maximum integer of nums is 5. It can be shown that the maximum number cannot be less than 5.
Therefore, we return 5.

Example 2:

Input: nums = [10,1]
Output: 10
Explanation:
It is optimal to leave nums as is, and since 10 is the maximum value, we return 10.

这道题重要的是后面的大的数要匀出来给前面小的数 所以可以定义一个limit, 并且需要从后往前模拟 如果 nums[i]>limit,那么应当去掉多余的 nums[i]−limit加到 nums[i−1] 上,最后如果 nums[0] + extra ≤limit,则二分判定成功。

最大化最小值求二分的时候,最重要的是写清楚check函数

class Solution {
  
    public int minimizeArrayValue(int[] nums) {
        int left = 0;
        int max = 0;
        for (int n : nums) {
            max = Math.max(n, max);
        }

        int right = max;

        while (left < right) {
            int mid = left + (right - left) / 2;
            if (check(nums, mid)) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        return left;
    }

    private boolean check(int[] nums, int limit) {
        long extra = 0;
        
        for (int i = nums.length - 1; i > 0; i--) {
            extra = Math.max(nums[i] + extra - limit, 0);
        }
        return nums[0] + extra <= limit;
    }
    
}

2513. Minimize the Maximum of Two Arrays

We have two arrays arr1 and arr2 which are initially empty. You need to add positive integers to them such that they satisfy all the following conditions:

  • arr1 contains uniqueCnt1 distinct positive integers, each of which is not divisible by divisor1.
  • arr2 contains uniqueCnt2 distinct positive integers, each of which is not divisible by divisor2.
  • No integer is present in both arr1 and arr2.

Given divisor1divisor2uniqueCnt1, and uniqueCnt2, return the minimum possible maximum integer that can be present in either array.

 

Example 1:

Input: divisor1 = 2, divisor2 = 7, uniqueCnt1 = 1, uniqueCnt2 = 3
Output: 4
Explanation: 
We can distribute the first 4 natural numbers into arr1 and arr2.
arr1 = [1] and arr2 = [2,3,4].
We can see that both arrays satisfy all the conditions.
Since the maximum value is 4, we return it.

Example 2:

Input: divisor1 = 3, divisor2 = 5, uniqueCnt1 = 2, uniqueCnt2 = 1
Output: 3
Explanation: 
Here arr1 = [1,2], and arr2 = [3] satisfy all conditions.
Since the maximum value is 3, we return it.

Example 3:

Input: divisor1 = 2, divisor2 = 4, uniqueCnt1 = 8, uniqueCnt2 = 2
Output: 15
Explanation: 
Here, the final possible arrays can be arr1 = [1,3,5,7,9,11,13,15], and arr2 = [2,6].
It can be shown that it is not possible to obtain a lower maximum satisfying all conditions. 

这道题首先要确定边界,最坏的情况就是divisor1和divisor2都是2,只能取奇数 所以最大值就是2*(uniqueCnt1 + uniqueCnt2)
其次是check函数:v 要满足三个条件:(v - 能被d1整除不能用的数 >= uniqueCnt1) && (v - 能被d2整除不能用的数 >= uniqueCnt2) && (v - 能被lcm整除都不能用的数 >= uniqueCnt1 + uniqueCnt2)

class Solution {
    public int minimizeSet(int divisor1, int divisor2, int uniqueCnt1, int uniqueCnt2) {
        long left = -1;
        long right = 2 * (uniqueCnt1 + uniqueCnt2);
        while(left + 1 < right) {
            long mid = left + (right - left) / 2;
            if(check(divisor1, divisor2, uniqueCnt1, uniqueCnt2, mid)) {
                right = mid;
            } else {
                left = mid;
            }
        }
        return (int) right;
    }

    public boolean check(int divisor1, int divisor2, int uniqueCnt1, int uniqueCnt2, long limit) {
        long num1 = limit - limit / findLCM(divisor1, divisor2);
        long num2 = limit - limit / divisor1;
        long num3 = limit - limit / divisor2;
        
        if(uniqueCnt1 <= num2 && uniqueCnt2 <= num3 && ((uniqueCnt1 + uniqueCnt2) <= num1))         {
            return true;
        } else {
            return false;
        }
    }

     public long findLCM(long a, long b) {
        return (a * b) / findGCD(a, b);
    }


    public long findGCD(long a, long b) {
        while (b != 0) {
            long temp = b;
            b = a % b;
            a = temp;
        }
        return a;
    }
}

2560. House Robber IV

There are several consecutive houses along a street, each of which has some money inside. There is also a robber, who wants to steal money from the homes, but he refuses to steal from adjacent homes.

The capability of the robber is the maximum amount of money he steals from one house of all the houses he robbed.

You are given an integer array nums representing how much money is stashed in each house. More formally, the ith house from the left has nums[i] dollars.

You are also given an integer k, representing the minimum number of houses the robber will steal from. It is always possible to steal at least k houses.

Return the minimum capability of the robber out of all the possible ways to steal at least k houses.

 

Example 1:

Input: nums = [2,3,5,9], k = 2
Output: 5
Explanation: 
There are three ways to rob at least 2 houses:
- Rob the houses at indices 0 and 2. Capability is max(nums[0], nums[2]) = 5.
- Rob the houses at indices 0 and 3. Capability is max(nums[0], nums[3]) = 9.
- Rob the houses at indices 1 and 3. Capability is max(nums[1], nums[3]) = 9.
Therefore, we return min(5, 9, 9) = 5.

Example 2:

Input: nums = [2,7,9,3,1], k = 2
Output: 2
Explanation: There are 7 ways to rob the houses. The way which leads to minimum capability is to rob the house at index 0 and 4. Return max(nums[0], nums[4]) = 2.

这道题也是可以用二分法来做的 check function可以用传统的打家劫舍方法来做

class Solution {
    public int minCapability(int[] nums, int k) {
        int left = 0;
        int max = nums[0];
        for(int i = 1; i < nums.length; i++) {
            max = Math.max(max, nums[i]);
        }
        int right = max + 1;

        while(left + 1 < right) {
            int mid = left + (right - left) / 2;
            if(check(nums, mid, k)) {
                right = mid;
            } else {
                left = mid;
            }
        }
        return right;
    }
    public boolean check(int[] nums, int mid, int k) {
        int f0 = 0, f1 = 0;
        for (int x : nums)
            if (x > mid) f0 = f1;
            else {
                int tmp = f1;
                f1 = Math.max(f1, f0 + 1);
                f0 = tmp;
            }
        return f1 >= k;
    }
}

最小化最大值

1552. Magnetic Force Between Two Balls

In the universe Earth C-137, Rick discovered a special form of magnetic force between two balls if they are put in his new invented basket. Rick has n empty baskets, the ith basket is at position[i], Morty has m balls and needs to distribute the balls into the baskets such that the minimum magnetic force between any two balls is maximum.

Rick stated that magnetic force between two different balls at positions x and y is |x - y|.

Given the integer array position and the integer m. Return the required force.

 

Example 1:

Input: position = [1,2,3,4,7], m = 3
Output: 3
Explanation: Distributing the 3 balls into baskets 1, 4 and 7 will make the magnetic force between ball pairs [3, 3, 6]. The minimum magnetic force is 3. We cannot achieve a larger minimum magnetic force than 3.

Example 2:

Input: position = [5,4,3,2,1,1000000000], m = 2
Output: 999999999
Explanation: We can use baskets 1 and 1000000000.

最大化最小值和最小化最大值的解题思路差不多,不同的就是当check函数成立时,是选择右边还是选择左边
这道题的check函数不难实现,只要看看最终结果是否大于m就好

class Solution {
    Map<Integer, Integer> map = new HashMap<>();
    public int maxDistance(int[] position, int m) {
        Arrays.sort(position);
        int n = position.length;
        int left = -1;
        int right = position[n-1] - position[0] + 1;

        while(left + 1 < right) {
            int mid = left + (right - left) / 2;
            if(check(position, mid, m)) {
                left = mid;
            } else {
                right = mid;
            }
        }
        return left;
    }

    public boolean check(int[] position, int mid, int m) {
        int idx = position[0];
        int num = 1;
        for(int i = 1; i < position.length; i++) {
            if(idx + mid > position[i]) {
                continue;
            } else {
                idx = position[i];
                num++;
            }
        }
        // System.out.println(mid + " " + m + " " + (num >= m));
        return num >= m;
    }
}

2517和这道题一样,只是换了个叙述场景,代码可以复用