标签:right target nums int Light mid Minimum Radius left
Minimum Light Radius - 二分查找
题目地址
binarysearch.com/problems/Minimum-Light-Radius
题目描述
思路
- 首先,思考了一下给的nums数组是不是有序的,事实证明是无序的,那先排个序
- 因为半径可能有小数,比较麻烦,可以改成求最小直径,因为房子的坐标都是整数,那直径是房子坐标的差也一定是整数
- 因为有三盏灯,直径的最大值是最右侧房子和最左侧房子坐标之差的1/3,因此右指针初始化为
right = (nums[-1] - nums[0]) // 3
- 如果当前直径mid可以覆盖所有的房子(allCovered == True),当前mid可能偏大,也可能就是最小直径,令
right= mid - 1
(如果确实偏大就丢弃了,如果确实是最小直径那循环会停止,left就是最小直径,返回left / 2
) - 如果当前直径mid不可以覆盖所有房子(allCovered == False),当前mid偏小,增大mid,
left = mid + 1
- 找到最小直径left后返回left的一半即为最小半径
- 判断是否可以覆盖所有房子的方法:
- 三盏灯中的两盏肯定是放在两边的,就看中间那盏灯能不能覆盖剩下的房子,也就是看除去左右两盏灯覆盖的范围后的中间区域的房子的左右边界之差有没有比最小直径更小。
- 通过二分法找中间区域房子的左边界leftBorder和右边界rightBorder
- 如果右边界超出索引范围返回True
(只有nums中地址不重复的房子数量<=3的时候会超出边界,这时候一定是返回True的)
- 如果左右边界之差小于等于一盏灯可以覆盖的范围,返回True
- 如果左右边界之差大于一盏灯可以覆盖的范围,返回False
代码(Python3)
class Solution:
def solve(self, nums):
nums.sort()
left = 0
right = (nums[-1] - nums[0]) // 3
while left <= right:
mid = (left + right) // 2
if self.allCovered(mid, nums):
right = mid - 1
else:
left = mid + 1
return left / 2
def allCovered(self, d, nums):
# 1. 二分法找左边界
target = nums[0] + d
left = 0
right = len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] > target:
# 是我们想要的,但我们更想要满足条件的最小mid
right = mid - 1
else:
left = mid + 1
leftBorder = left
# 2. 二分法找右边界
target = nums[-1] - d
left = 0
right = len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] < target:
# 是我们想要的,但我们更想要满足条件的最大mid
left = mid + 1
else:
right = mid - 1
rightBorder = right
if rightBorder < 0 or nums[rightBorder] - nums[leftBorder] <= d:
return True
else:
return False
代码(Java)
import java.util.*;
class Solution {
public double solve(int[] nums) {
Arrays.sort(nums);
int n = nums.length;
int left = 0, right = (nums[n - 1] - nums[0]) / 3;
while(left <= right){
int mid = (left + right) / 2;
if(allCovered(mid, nums)){
right = mid - 1;
}else{
left = mid + 1;
}
}
return left / 2.0;
}
private boolean allCovered(int d, int[] nums){
int target = nums[0] + d, n = nums.length;
int left = 0, right = n - 1;
while(left <= right){
int mid = (left + right) / 2;
if(nums[mid] > target){
right = mid - 1;
}else{
left = mid + 1;
}
}
int leftBorder = left;
target = nums[n - 1] - d;
left = 0;
right = n - 1;
while(left <= right){
int mid = (left + right) / 2;
if(nums[mid] < target){
left = mid + 1;
}else{
right = mid - 1;
}
}
int rightBorder = right;
if(rightBorder < 0 || nums[rightBorder] - nums[leftBorder] <= d){
return true;
}else{
return false;
}
}
}
复杂度分析
- 时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn),排序最费时
- 空间复杂度: O ( 1 ) O(1) O(1)
标签:right,target,nums,int,Light,mid,Minimum,Radius,left 来源: https://blog.csdn.net/qq_41726606/article/details/114365611
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。