算法笔记之二分法解决极小化极大 问题引入: 1 2 3 4 5 6 7 8 Rick 有 n 个空的篮子,第 i 个篮子的位置在 position[i] ,Morty 想把 m 个球放到这些篮子里,使得任意两球间 最小磁力 最大。 已知两个球如果分别位于 x 和 y ,那么它们之间的磁力为 |x - y| 。 给你一个整数数组 position 和一个整数 m ,请你返回最大化的最小磁力。 n == position.length 2 <= n <= 10^5 1 <= position[i] <= 10^9 所有 position 中的整数 互不相同 。 2 <= m <= position.length
问题分析:
题目要求返回最大化的最小磁力,这是这类问题的一个典型的标志 。
正向分析题目,很难去解决。利用动态规划,贪心还是DFS都很棘手。
但是,这个时候反过来从结果出发,能不能枚举所有可能的最小磁力获得最大的磁力呢?
枚举是可以实现的,以为最小磁力可能出现的区间就是1到数组间隔最大值。
同时,结果的集合又呈单调性。在某个临界点之前都符合题意,之后的所有可能都不符合。
对于这种单调性的问题,二分法就是很好的解决方案了。
结论:从结果出发,二分搜索结果。见到极小化极大,极大化极小的问题,就可以考虑二分法
解题思路:
根据题目的数据范围,二分法搜索的区间是[0,pos[n]-pos[0]] ;
二分法的关键就是如何判定某个点是符合的:设k为某个最小的磁力,那么看数组上以k为距离可以放置多少小球,个数>m成立。
二分法另外一个复杂的点在于边界控制问题。
代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public int maxMinDist (int [] position,int m) { Arrays.sort(position); int n = position.length; int l=0 ,r=position[n-1 ]; while (l<r){ int mid = (l+r+1 )>>1 ; if (checkMid(mid,n,m,position)){ l = mid; }else { r = mid-1 ; } } return l; } public boolean checkMid (int mid,int n,int m,int [] position) { int cnt = 1 ,temp = 0 ; for (int i=1 ;i<n;i++){ if (position[i]-position[temp]>=mid){ cnt++; temp=i; } } return cnt>=m; }