二分法(binary search)系列 35, 33, 81, 153, 154, 278, 4, 367, 69, 436, 1060, 1062, 410,2616, 1539, 162, 34, 3296, 792, 1011
Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You must write an algorithm with O(log n)
runtime complexity.
Example 1:
Input: nums = [1,3,5,6], target = 5
Output: 2
Example 2:
Input: nums = [1,3,5,6], target = 2
Output: 1
Example 3:
Input: nums = [1,3,5,6], target = 7
Output: 4
Example 4:
Input: nums = [1,3,5,6], target = 0
Output: 0
Example 5:
Input: nums = [1], target = 0
Output: 0
Constraints:
1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums
contains distinct values sorted in ascending order.-104 <= target <= 104
解法一:这种解法可以用于处理一些简单的二分法问题
class Solution {
public int searchInsert(int[] nums, int target) {
int l=0,r=nums.length-1;
while(l+1<r){
int mid = l+(r-l)/2;
if(nums[mid]==target) return mid;
else if(nums[mid]>target) r=mid;
else l=mid+1;
}
if(nums[l]>=target) return l;
else if(nums[r]>=target) return r;
else return r+1;
}
}
解法二:
l 和 r 所定义的出的数组范围为 [l, r), 是 左闭右开 的 也就是在后续的循环中, r 所指向的位置是 不被 包括在循环以内的, r 所代表的位置实际上是要查找的数组的最后一个元素的后一个元素。
因为是 左闭右开 的 r 初值为 nums.size() ,因为数组的最后一个元素的索引为 nums[nums.length - 1], 根据 r 定义最后一个元素的后一个元素即为 r = nums.length;
因为是 左闭右开 的循环结束条件的判断中为 while(l < r) 因为对于左闭右开的区间 [2, 2) 这种数值是无意义的, 所以当 r = l 的时候, 就该结束循环了, 所以只有在 l < r 才继续循环
因为是 左闭右开 的 r 的移动规则为 r = mid ,因为当前循环查找的为索引为 mid 位置的元素(即:(nums[mid] == target)), 下一次应该将查找范围的右边界设置为 mid 位置的前一个元素([l, m - 1]), 因为 r 指向最后一个元素的后一个元素, 当 r = m , 下次的查找范围就为 [l, r)即 [l, m - 1]
class Solution {
public int searchInsert(int[] nums, int target) {
int l=0,r=nums.length;
while(l<r){
int mid = l+(r-l)/2;
if(nums[mid]==target) return mid;
else if(nums[mid]>target) r=mid;
else l=mid+1;
}
return l;
}
}
这个地方可以想一下,假如我们把r=nums.length-1 会怎么样? 这样的话,你的mid算出来永远都够不到最后一个元素(nums.length-1),如果最后一个元素是target的话,就会有问题
class Solution {
public int searchInsert(int[] nums, int target) {
int l=0,r=nums.length-1;
while(l<r){
int mid = l+(r-l)/2;
if(nums[mid]==target) return mid;
else if(nums[mid]>target) r=mid;
else l=mid+1;
}
return l;
}
}
解法三:
常规写法 1 中 l 和 r 的定义的范围为 [l, r],是 左闭右闭 的也就是在后续的循环中, r 所指向的位置是 被 包括在循环以内的, r 所代表的位置实际上是要查找的数组的最后一个元素。
因为是 左闭右闭 的 r 初值应为 nums.length - 1 ,因为数组的最后一个元素的索引为 nums[nums.length - 1], 根据 r 定义 最后一个元素 即为 r = nums.length - 1;
因为是 左闭右闭 循环结束条件的判断中为 while(l < r) ,因为对于左闭右闭的区间 [2, 2] 这种数值是有意义的(包含元素 2), 所以当 r = l 的时候, 还有一个元素应该去查找, 所以 l <= r 继续循环
因为是 左闭右闭 r 的移动规则为 r = mid - 1 ,因为当前循环被查找的为索引为 m 位置的元素(即:(nums[mid] == target)) , 下一次应该将查找范围的右边界设置为 m 位置的前一个元素([l, mid - 1]), 因为 r 指向最后一个元素 , 所以让 r = mid - 1 , 下次的查找范就为 [l, r - 1] 即 [l, mid - 1]
class Solution {
public int searchInsert(int[] nums, int target) {
int l=0,r=nums.length-1;
while(l<=r){
int mid = l+(r-l)/2;
if(nums[mid]==target) return mid;
else if(nums[mid]>target) r=mid-1;
else l=mid+1;
}
return l;
}
}
There is an integer array nums
sorted in ascending order (with distinct values).
Prior to being passed to your function, nums
is possibly rotated at an unknown pivot index k
(1 <= k < nums.length
) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]
(0-indexed). For example, [0,1,2,4,5,6,7]
might be rotated at pivot index 3
and become [4,5,6,7,0,1,2]
.
Given the array nums
after the possible rotation and an integer target
, return the index of target
if it is in nums
, or -1
if it is not in nums
.
You must write an algorithm with O(log n)
runtime complexity.
Example 1:
Input: nums = [4,5,6,7,0,1,2], target = 0 Output: 4
Example 2:
Input: nums = [4,5,6,7,0,1,2], target = 3 Output: -1
Example 3:
Input: nums = [1], target = 0 Output: -1
Constraints:
1 <= nums.length <= 5000
-104 <= nums[i] <= 104
- All values of
nums
are unique. nums
is an ascending array that is possibly rotated.-104 <= target <= 104
解法一: 二分法找到rotate的那个点(最小值位置),再用一个二分法搜索target对应的半部分
class Solution { public int search(int[] nums, int target) { int len = nums.length; if(nums[len-1]==target) return len-1; //1.find the switch point int l=0,r=len-1; while(l<r){ int mid = l+(r-l)/2; if(nums[mid]>nums[len-1]) l=mid+1; else r=mid; } int pivot = r; //2.base on the switch point to do binarysearch if(nums[len-1]<target){ l = 0; r = pivot; } else{ l=pivot; r = len; } //3.do binarysearch in the sorted arr while(l<r){ int mid = l+(r-l)/2; if(nums[mid]>target) r=mid; else if(nums[mid]<target) l=mid+1; else return mid; } return -1; } }
解法二:递归二分解决
图一
图二
class Solution { public int search(int[] nums, int target) { return helper(nums,target,0,nums.length-1); } private int helper(int[] a,int target,int start,int end){ int mid = start+(end-start)/2; if(a[mid]==target) return mid; if(start>=end) return -1;
//图一的情况 if(a[mid]>=a[start]){//包含等于
//落在图一的蓝色部分 if(a[start]<=target && target<a[mid]) //包含等于 return helper(a,target,start,mid-1);
//落在图一的黑色部分 else return helper(a,target,mid+1,end); }
//图二的情况 else{
//落在图二的黑色部分 if(a[mid]<target && target<=a[end]) //包含等于 return helper(a,target,mid+1,end);
//落在图一的蓝色部分 else return helper(a,target,start,mid-1); } } }
class Solution { public int search(int[] nums, int target) { int left = 0,right = nums.length-1; while(left<right){ int pivot = nums[left]; if(pivot==target) return left; int mid = left+(right-left)/2; if(nums[mid]==target) return mid; if(nums[mid]>=pivot){//图一的情况 if(target<nums[mid] && target>=pivot) right=mid-1; else left=mid+1; } else{//图二的情况 if(target>nums[mid] && target<pivot) left=mid+1; else right=mid-1; } } return nums[left]==target ? left : -1; } }
There is an integer array nums
sorted in non-decreasing order (not necessarily with distinct values).
Before being passed to your function, nums
is rotated at an unknown pivot index k
(0 <= k < nums.length
) such that the resulting array is [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]
(0-indexed). For example, [0,1,2,4,4,4,5,6,6,7]
might be rotated at pivot index 5
and become [4,5,6,6,7,0,1,2,4,4]
.
Given the array nums
after the rotation and an integer target
, return true
if target
is in nums
, or false
if it is not in nums
.
You must decrease the overall operation steps as much as possible.
Example 1:
Input: nums = [2,5,6,0,0,1,2], target = 0 Output: true
Example 2:
Input: nums = [2,5,6,0,0,1,2], target = 3 Output: false
Constraints:
1 <= nums.length <= 5000
-104 <= nums[i] <= 104
nums
is guaranteed to be rotated at some pivot.-104 <= target <= 104
解法: 跟上一题类似,只不过出现了很多相等的点,当你的start或end落在了相等点集合中的时候,你很难判断是上升阶段还是下降阶段,因此我们碰到相等的点直接左移或右移。
class Solution { public boolean search(int[] nums, int target) { return helper(nums,target,0,nums.length-1); } private boolean helper(int[] nums, int target,int l,int r){ //跳过相等的点 while(l<r && nums[l]==nums[l+1]) l++; while(l<r && nums[r]==nums[r-1]) r--; while(l<=r){ int mid = l+(r-l)/2; if(nums[mid]==target) return true; if(nums[mid]>=nums[l]){ if(nums[l]<=target && target<nums[mid]) return helper(nums,target,l,mid-1); else return helper(nums,target,mid+1,r); } else{ if(nums[mid]<target && target<=nums[r]) return helper(nums,target,mid+1,r); else return helper(nums,target,l,mid-1); } } return false; } }
Suppose an array of length n
sorted in ascending order is rotated between 1
and n
times. For example, the array nums = [0,1,2,4,5,6,7]
might become:
[4,5,6,7,0,1,2]
if it was rotated4
times.[0,1,2,4,5,6,7]
if it was rotated7
times.
Notice that rotating an array [a[0], a[1], a[2], ..., a[n-1]]
1 time results in the array [a[n-1], a[0], a[1], a[2], ..., a[n-2]]
.
Given the sorted rotated array nums
of unique elements, return the minimum element of this array.
You must write an algorithm that runs in O(log n) time.
Example 1:
Input: nums = [3,4,5,1,2] Output: 1 Explanation: The original array was [1,2,3,4,5] rotated 3 times.
Example 2:
Input: nums = [4,5,6,7,0,1,2] Output: 0 Explanation: The original array was [0,1,2,4,5,6,7] and it was rotated 4 times.
Example 3:
Input: nums = [11,13,15,17] Output: 11 Explanation: The original array was [11,13,15,17] and it was rotated 4 times.
Constraints:
n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
- All the integers of
nums
are unique. nums
is sorted and rotated between1
andn
times.
解法: 我们可以想象,要寻找的是第一个小于末尾元素的元素
class Solution { public int findMin(int[] nums) { if(nums.length==1) return nums[0]; int l=0,r=nums.length-2; int pivot = nums[nums.length-1]; while(l<r){ int mid = l+(r-l)/2; if(nums[mid]>pivot) l=mid+1; else r=mid; } if(nums[l]<pivot) return nums[l]; return pivot; } }
Suppose an array of length n
sorted in ascending order is rotated between 1
and n
times. For example, the array nums = [0,1,4,4,5,6,7]
might become:
[4,5,6,7,0,1,4]
if it was rotated4
times.[0,1,4,4,5,6,7]
if it was rotated7
times.
Notice that rotating an array [a[0], a[1], a[2], ..., a[n-1]]
1 time results in the array [a[n-1], a[0], a[1], a[2], ..., a[n-2]]
.
Given the sorted rotated array nums
that may contain duplicates, return the minimum element of this array.
You must decrease the overall operation steps as much as possible.
Example 1:
Input: nums = [1,3,5] Output: 1
Example 2:
Input: nums = [2,2,2,0,1] Output: 0
Constraints:
n == nums.length
1 <= n <= 5000
-5000 <= nums[i] <= 5000
nums
is sorted and rotated between1
andn
times.
解法: 需要类似上上一道题,遇到重复的左移或者右移,另外如果开头结尾相等的,直接左移
class Solution { public int findMin(int[] nums) { if(nums.length==1) return nums[0]; int l=0,r=nums.length-2; int pivot = nums[nums.length-1]; while(l<r && nums[l]==nums[l+1]) l++; while(l<r && nums[r]==nums[r-1]) r--; if(nums[l]==nums[r]) r--; while(l<r){ int mid = l+(r-l)/2; if(nums[mid]>=pivot) l=mid+1; else r=mid; } if(nums[l]<pivot) return nums[l]; return pivot; } }
278. First Bad Version
You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad.
Suppose you have n
versions [1, 2, ..., n]
and you want to find out the first bad one, which causes all the following ones to be bad.
You are given an API bool isBadVersion(version)
which returns whether version
is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API.
Example 1:
Input: n = 5, bad = 4 Output: 4 Explanation: call isBadVersion(3) -> false call isBadVersion(5) -> true call isBadVersion(4) -> true Then 4 is the first bad version.
Example 2:
Input: n = 1, bad = 1 Output: 1
Constraints:
1 <= bad <= n <= 231 - 1
/* The isBadVersion API is defined in the parent class VersionControl. boolean isBadVersion(int version); */ public class Solution extends VersionControl { public int firstBadVersion(int n) {
//注意这里的version我是从0到n-1判断的,所以最终返回结果需要+1 int l=0,r=n-1; while(l<r){ int mid = l+(r-l)/2; //如果badversion,此处不能是r=mid-1,因为我们要找的是第一个badversion,也许当前mid就是第一个badversion了 if(isBadVersion(mid+1)) r=mid; //如果不是badversion,那么可以l=mid+1,因为我们要找的badversion,可以跳过当前这个了 else l=mid+1; } return l+1; } }
Given two sorted arrays nums1
and nums2
of size m
and n
respectively, return the median of the two sorted arrays.
The overall run time complexity should be O(log (m+n))
.
Example 1:
Input: nums1 = [1,3], nums2 = [2] Output: 2.00000 Explanation: merged array = [1,2,3] and median is 2.
Example 2:
Input: nums1 = [1,2], nums2 = [3,4] Output: 2.50000 Explanation: merged array = [1,2,3,4] and median is (2 + 3) / 2 = 2.5.
Example 3:
Input: nums1 = [0,0], nums2 = [0,0] Output: 0.00000
Example 4:
Input: nums1 = [], nums2 = [1] Output: 1.00000
Example 5:
Input: nums1 = [2], nums2 = [] Output: 2.00000
Constraints:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106
1.保证第一个数组长度小于等于第二个数组,这样对第一个数组无论如何切分,第二个数组切分点永远不会越界
2.计算第二个数组的切分点会比较tricky ,int y = (m+n+1)/2 - x 得通过举例得出
class Solution { public double findMedianSortedArrays(int[] nums1, int[] nums2) { if(nums1.length>nums2.length) return findMedianSortedArrays(nums2,nums1); int m = nums1.length,n=nums2.length; int l=0,r=m; while(l<=r){ int x = l+(r-l)/2; int y = (m+n+1)/2 - x; int xl = x==0 ? Integer.MIN_VALUE : nums1[x-1]; int xr = x==m ? Integer.MAX_VALUE : nums1[x]; int yl = y==0 ? Integer.MIN_VALUE : nums2[y-1]; int yr = y==n ? Integer.MAX_VALUE : nums2[y]; if(xl<=yr && yl<=xr){ if((m+n)%2==0) return ((double)(Math.max(xl,yl)+Math.min(xr,yr)))/2; else return Math.max(xl,yl); } else if(xl>yr) r = x-1; else l = x+1; } return 0; } }
class Solution: def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float: def find(nums1, nums2): #确保左侧数组不长于右侧数组 if len(nums1) > len(nums2): return find(nums2, nums1) len1, len2 = len(nums1), len(nums2) s1, e1 = 0, len1 while s1 <= e1: #第一个数组左侧分得元素个数 part1 = (s1 + e1) // 2 #第二个数组左侧分得元素个数 part2 = (len1 + len2 + 1) // 2 - part1 #计算两个数组切割点两侧的元素值 arr1Left = -1000000 if part1 == 0 else nums1[part1 - 1] arr1Right = 1000000 if part1 == len1 else nums1[part1] arr2Left = -1000000 if part2 == 0 else nums2[part2 - 1] arr2Right = 1000000 if part2 == len2 else nums2[part2] #如果第一个的左侧大于第二个的右侧,说明第一个数组切割太靠右了,需要向左移动 if arr1Left > arr2Right: #too right , need to go <--- e1 = part1 - 1 #如果第二个的左侧大于第一个的右侧,说明第一个数组切割太靠左了,需要向右移动 elif arr2Left > arr1Right: #too left, need to go --> s1 = part1 + 1 else: if (len1 + len2) % 2 == 0: return (max(arr1Left, arr2Left) + min(arr1Right, arr2Right)) / 2 return max(arr1Left, arr2Left) return find(nums1, nums2)
Given a positive integer num, write a function which returns True if num is a perfect square else False.
Follow up: Do not use any built-in library function such as sqrt
.
Example 1:
Input: num = 16 Output: true
Example 2:
Input: num = 14 Output: false
Constraints:
1 <= num <= 2^31 - 1
这个题的坑点:num过大时很容易越界,因此mid要定义为long类型
class Solution { public boolean isPerfectSquare(int num) { long left = 1,right = num; while(left<right){ long mid = left+(right-left)/2; long squre = mid*mid; if(squre>num) right=mid; else if(squre<num) left=mid+1; else return true; } return left*left==num; } }
Given a non-negative integer x
, compute and return the square root of x
.
Since the return type is an integer, the decimal digits are truncated, and only the integer part of the result is returned.
Note: You are not allowed to use any built-in exponent function or operator, such as pow(x, 0.5)
or x ** 0.5
.
Example 1:
Input: x = 4 Output: 2
Example 2:
Input: x = 8 Output: 2 Explanation: The square root of 8 is 2.82842..., and since the decimal part is truncated, 2 is returned.
Constraints:
0 <= x <= 231 - 1
class Solution { public int mySqrt(int x) { long left = 0,right = x; while(left<=right){ long mid = left+(right-left)/2; if(mid*mid<=x) left=mid+1; else right=mid-1; } return (int)right; } }
436. Find Right Interval
You are given an array of intervals
, where intervals[i] = [starti, endi]
and each starti
is unique.
The right interval for an interval i
is an interval j
such that startj
>= endi
and startj
is minimized.
Return an array of right interval indices for each interval i
. If no right interval exists for interval i
, then put -1
at index i
.
Example 1:
Input: intervals = [[1,2]] Output: [-1] Explanation: There is only one interval in the collection, so it outputs -1.
Example 2:
Input: intervals = [[3,4],[2,3],[1,2]] Output: [-1,0,1] Explanation: There is no right interval for [3,4]. The right interval for [2,3] is [3,4] since start0 = 3 is the smallest start that is >= end1 = 3. The right interval for [1,2] is [2,3] since start1 = 2 is the smallest start that is >= end2 = 2.
Example 3:
Input: intervals = [[1,4],[2,3],[3,4]] Output: [-1,2,-1] Explanation: There is no right interval for [1,4] and [3,4]. The right interval for [2,3] is [3,4] since start2 = 3 is the smallest start that is >= end1 = 3.
Constraints:
1 <= intervals.length <= 2 * 104
intervals[i].length == 2
-106 <= starti <= endi <= 106
- The start point of each interval is unique.
class Solution { public int[] findRightInterval(int[][] intervals) { Map<Integer,Integer> map = new HashMap(); int[] arr = new int[intervals.length]; for(int i=0;i<intervals.length;i++){ int[] pair = intervals[i]; map.put(pair[0],i); arr[i]=pair[0]; } Arrays.sort(arr); int[] result = new int[intervals.length]; for(int i=0;i<intervals.length;i++){ int pos= search(arr,intervals[i][1]); if(pos<0) result[i]=-1; else result[i]=map.get(arr[pos]); } return result; }
//二分法第三种模版, 特点 1) left<=right 2) 满足条件时要记录结果,避免最终left/right交叉后再判定哪个是结果 private int search(int[] arr,int target){ int left = 0,right = arr.length-1; int result = -1; while(left<=right){ int mid = left+(right-left)/2; if(arr[mid]>=target) { right = mid-1; result = mid;//记录结果 } else left = mid+1; } return result;//返回结果 }
// 二分法第二种模版,特点:1) left<right 2) right初始为length 而不是length-1 3) right回缩的时候是 right=mid,而不是mid-1 // private int search(int[] arr,int target){ // int left = 0,right = arr.length; // while(left<right){ // int mid = left+(right-left)/2; // if(arr[mid]>=target) right = mid; // else left = mid+1; // } // return left>=arr.length ? -1 : left; // } }
Given an integer array nums
which is sorted in ascending order and all of its elements are unique and given also an integer k
, return the kth
missing number starting from the leftmost number of the array.
Example 1:
Input: nums = [4,7,9,10], k = 1 Output: 5 Explanation: The first missing number is 5.
Example 2:
Input: nums = [4,7,9,10], k = 3 Output: 8 Explanation: The missing numbers are [5,6,8,...], hence the third missing number is 8.
Example 3:
Input: nums = [1,2,4], k = 3 Output: 6 Explanation: The missing numbers are [3,5,6,7,...], hence the third missing number is 6.
Constraints:
1 <= nums.length <= 5 * 104
1 <= nums[i] <= 107
nums
is sorted in ascending order, and all the elements are unique.1 <= k <= 108
O(log(n))
) solution?class Solution { public int missingElement(int[] nums, int k) { int missing = getMissing(nums,nums.length-1);//计算当前数组中missing的个数 if(missing<k) return nums[nums.length-1]+k-missing;//如果k大于当前数组missing的个数,直接去末尾计算返回即可
//如果第k个在数组missing当中,用二分法去找exact k的位置 int left = 0,right = nums.length; while(left<right){ int mid = left+(right-left)/2; int curr = getMissing(nums,mid); if(curr<k) left=mid+1; else right = mid; }
//截止left的位置总是缺少的元素个数大于等于k,因此算第k个得从left的前一个元素开始算起 return nums[left-1]+k-getMissing(nums,left-1); } private int getMissing(int[] nums,int pos){ return nums[pos]-nums[0]-pos; } }
Given a string s
, return the length of the longest repeating substrings. If no repeating substring exists, return 0
.
Example 1:
Input: s = "abcd" Output: 0 Explanation: There is no repeating substring.
Example 2:
Input: s = "abbaba" Output: 2 Explanation: The longest repeating substrings are "ab" and "ba", each of which occurs twice.
Example 3:
Input: s = "aabcaabdaab"
Output: 3
Explanation: The longest repeating substring is "aab", which occurs 3
times.
Constraints:
1 <= s.length <= 2000
s
consists of lowercase English letters.
class Solution { public int search(int L, int n, String S) { HashSet<String> seen = new HashSet(); String tmp; for(int start = 0; start < n - L + 1; ++start) { tmp = S.substring(start, start + L); if (seen.contains(tmp)) return start; seen.add(tmp); } return -1; } public int longestRepeatingSubstring(String S) { int n = S.length(); // binary search, L = repeating string length int left = 1, right = n; int L; while (left <= right) { L = left + (right - left) / 2; if (search(L, n, S) != -1) left = L + 1; else right = L - 1; } return left - 1; } }
You are given a 0-indexed array of positive integers w
where w[i]
describes the weight of the ith
index.
You need to implement the function pickIndex()
, which randomly picks an index in the range [0, w.length - 1]
(inclusive) and returns it. The probability of picking an index i
is w[i] / sum(w)
.
- For example, if
w = [1, 3]
, the probability of picking index0
is1 / (1 + 3) = 0.25
(i.e.,25%
), and the probability of picking index1
is3 / (1 + 3) = 0.75
(i.e.,75%
).
Example 1:
Input ["Solution","pickIndex"] [[[1]],[]] Output [null,0] Explanation Solution solution = new Solution([1]); solution.pickIndex(); // return 0. The only option is to return 0 since there is only one element in w.
Example 2:
Input ["Solution","pickIndex","pickIndex","pickIndex","pickIndex","pickIndex"] [[[1,3]],[],[],[],[],[]] Output [null,1,1,1,1,0] Explanation Solution solution = new Solution([1, 3]); solution.pickIndex(); // return 1. It is returning the second element (index = 1) that has a probability of 3/4. solution.pickIndex(); // return 1 solution.pickIndex(); // return 1 solution.pickIndex(); // return 1 solution.pickIndex(); // return 0. It is returning the first element (index = 0) that has a probability of 1/4. Since this is a randomization problem, multiple answers are allowed. All of the following outputs can be considered correct: [null,1,1,1,1,0] [null,1,1,1,1,1] [null,1,1,1,0,0] [null,1,1,1,0,1] [null,1,0,1,0,0] ...... and so on.
Constraints:
1 <= w.length <= 104
1 <= w[i] <= 105
pickIndex
will be called at most104
times.
class Solution { int[] presum; Random random ; public Solution(int[] w) { presum = new int[w.length]; presum[0] = w[0]; for(int i=1;i<w.length;i++){ presum[i] = presum[i-1]+w[i]; } random = new Random(); } public int pickIndex() { double target = presum[presum.length-1] * Math.random(); int pos = bs(presum, target); return pos; } private int bs(int[] arr, double target){ int left = 0, right = arr.length; while(left < right){ int mid = left+(right-left)/2; if(arr[mid] > target) right = mid; else if(arr[mid] == target) return mid; else left = mid+1; } return left; } }
Given an array nums
which consists of non-negative integers and an integer m
, you can split the array into m
non-empty continuous subarrays.
Write an algorithm to minimize the largest sum among these m
subarrays.
Example 1:
Input: nums = [7,2,5,10,8], m = 2 Output: 18 Explanation: There are four ways to split nums into two subarrays. The best way is to split it into [7,2,5] and [10,8], where the largest sum among the two subarrays is only 18.
Example 2:
Input: nums = [1,2,3,4,5], m = 2 Output: 9
Example 3:
Input: nums = [1,4,4], m = 3 Output: 4
Constraints:
1 <= nums.length <= 1000
0 <= nums[i] <= 106
1 <= m <= min(50, nums.length)
解法:如果通过组合的方式去判定的话,时间复杂度会比较高
我们可以采用猜数字的方法来解决,最小的结果应该是所有的数字都不组合:max(arr),最大的结果应该是将所有的数字加起来:sum(arr), 然后通过二分的方式去试探可行的最小解。
class Solution {
public int splitArray(int[] nums, int m) {
int max = Arrays.stream(nums).sum();
int min = Arrays.stream(nums).max().getAsInt();
while(min<max){
int mid = min+(max-min)/2;
if(valid(nums,m,mid))
max = mid;
else
min = mid+1;
}
return min;
}
private boolean valid(int[] nums, int m,int sum){
int count = 1;
int curr=0;
for(int i=0;i<nums.length;i++){
if(curr+nums[i]<=sum){
curr+=nums[i];
}
else{
count++;
curr=nums[i];
}
if(count>m) return false;
}
return true;
}
}
Koko loves to eat bananas. There are n
piles of bananas, the ith
pile has piles[i]
bananas. The guards have gone and will come back in h
hours.
Koko can decide her bananas-per-hour eating speed of k
. Each hour, she chooses some pile of bananas and eats k
bananas from that pile. If the pile has less than k
bananas, she eats all of them instead and will not eat any more bananas during this hour.
Koko likes to eat slowly but still wants to finish eating all the bananas before the guards return.
Return the minimum integer k
such that she can eat all the bananas within h
hours.
Example 1:
Input: piles = [3,6,7,11], h = 8 Output: 4
Example 2:
Input: piles = [30,11,23,4,20], h = 5 Output: 30
Example 3:
Input: piles = [30,11,23,4,20], h = 6 Output: 23
Constraints:
1 <= piles.length <= 104
piles.length <= h <= 109
1 <= piles[i] <= 109
class Solution { /* 解法,猜答案,使用二分法找到最佳答案 */ public int minEatingSpeed(int[] piles, int h) { int max = 0; for(int pile : piles){ max = Math.max(max, pile); } int left = 1, right = max, result = 0; while(left <= right){ int mid = left + (right - left)/2; if(valid(piles, mid, h)){ result = mid; right = mid - 1; } else{ left = mid + 1; } } return result; } private boolean valid(int[] piles, int k, int h){ for(int pile : piles){ h -= (pile + k - 1) / k; if(h < 0) return false; } return true; } }
You are given an array of positive integers price
where price[i]
denotes the price of the ith
candy and a positive integer k
.
The store sells baskets of k
distinct candies. The tastiness of a candy basket is the smallest absolute difference of the prices of any two candies in the basket.
Return the maximum tastiness of a candy basket.
Example 1:
Input: price = [13,5,1,8,21,2], k = 3 Output: 8 Explanation: Choose the candies with the prices [13,5,21]. The tastiness of the candy basket is: min(|13 - 5|, |13 - 21|, |5 - 21|) = min(8, 8, 16) = 8. It can be proven that 8 is the maximum tastiness that can be achieved.
Example 2:
Input: price = [1,3,1], k = 2 Output: 2 Explanation: Choose the candies with the prices [1,3]. The tastiness of the candy basket is: min(|1 - 3|) = min(2) = 2. It can be proven that 2 is the maximum tastiness that can be achieved.
Example 3:
Input: price = [7,7,7,7], k = 2 Output: 0 Explanation: Choosing any two distinct candies from the candies we have will result in a tastiness of 0.
Constraints:
2 <= k <= price.length <= 105
1 <= price[i] <= 109
class Solution { public int maximumTastiness(int[] price, int k) { Arrays.sort(price); int start = 0, end = price[price.length - 1] - price[0]; int result = 0; //二分搜索进行猜答案 while(start <= end){ int mid = start + (end - start) / 2; if(validate(price, k, mid)){ result = mid; start = mid + 1; } else{ end = mid - 1; } } return result; } //判断当前max是否符合条件 private boolean validate(int[] price, int k, int max) { int count = 1; int pre = 0; for(int i = 1; i < price.length; i++){ if(price[i] - price[pre] >= max){ count++; pre = i; } if(count >= k) return true; } return false; } }
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.
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.
Constraints:
1 <= nums.length <= 105
0 <= nums[i] <= 109
0 <= p <= (nums.length)/2
class Solution { public int minimizeMax(int[] nums, int p) { Arrays.sort(nums); int left = 0, right = nums[nums.length - 1]; int result = -1; while(left <= right) { int mid = left + (right - left) / 2; if(isValid(nums, p, mid)) { result = mid; right = mid - 1; } else{ left = mid + 1; } } return result; } //相差最大为guess的情况下,能否找到p对 private boolean isValid(int[] nums, int p, int guess) { int count = 0; for(int i = 1; i < nums.length; i++) { if(nums[i] - nums[i - 1] <= guess) { count++; i++; } } return count >= p; } }
Given an array arr
of positive integers sorted in a strictly increasing order, and an integer k
.
Return the kth
positive integer that is missing from this array.
Example 1:
Input: arr = [2,3,4,7,11], k = 5 Output: 9 Explanation: The missing positive integers are [1,5,6,8,9,10,12,13,...]. The 5th missing positive integer is 9.
Example 2:
Input: arr = [1,2,3,4], k = 2 Output: 6 Explanation: The missing positive integers are [5,6,7,...]. The 2nd missing positive integer is 6.
Constraints:
1 <= arr.length <= 1000
1 <= arr[i] <= 1000
1 <= k <= 1000
arr[i] < arr[j]
for1 <= i < j <= arr.length
Follow up:
Could you solve this problem in less than O(n) complexity?
class Solution { /** 正常应该是1,2,3,4,5 那么与数组value相比能看出来每个位置的gap, 然后我们通过二分搜索可以找到小于k个gap的最大index 然后在其基础上加k即为缺失的第k个数字 index: 0 1 2 3 4 normal: 1 2 3 4 5 value: 2, 3, 4, 7, 11 gap: 1 1 1 3 6 l r m k=5 */ public int findKthPositive(int[] arr, int k) { int left = 0, right = arr.length - 1; int pos = -1; while(left <= right) { int mid = left + (right - left) / 2; if(arr[mid] - mid - 1 < k) { pos = mid; left = mid + 1; } else{ right = mid - 1; } } return pos + k + 1; } }
A peak element is an element that is strictly greater than its neighbors.
Given a 0-indexed integer array nums
, find a peak element, and return its index. If the array contains multiple peaks, return the index to any of the peaks.
You may imagine that nums[-1] = nums[n] = -∞
. In other words, an element is always considered to be strictly greater than a neighbor that is outside the array.
You must write an algorithm that runs in O(log n)
time.
Example 1:
Input: nums = [1,2,3,1] Output: 2 Explanation: 3 is a peak element and your function should return the index number 2.
Example 2:
Input: nums = [1,2,1,3,5,6,4] Output: 5 Explanation: Your function can return either index number 1 where the peak element is 2, or index number 5 where the peak element is 6.
Constraints:
1 <= nums.length <= 1000
-231 <= nums[i] <= 231 - 1
nums[i] != nums[i + 1]
for all validi
.
class Solution { public int findPeakElement(int[] nums) { int left = 0, right = nums.length - 1; while(left < right) { int mid = left + (right - left) / 2; //如果mid<mid+1, 说明当前increasing 趋势,那么右侧必有peak if(nums[mid] < nums[mid + 1]) left = mid + 1; //如果mid>mid+1,说明当前decreasing 趋势,那么左侧必有peak else right = mid; //注意,无需考虑等于情况,因为题目说明相邻元素不会相等 } return left; } }
Given an array of integers nums
sorted in non-decreasing order, find the starting and ending position of a given target
value.
If target
is not found in the array, return [-1, -1]
.
You must write an algorithm with O(log n)
runtime complexity.
Example 1:
Input: nums = [5,7,7,8,8,10], target = 8 Output: [3,4]
Example 2:
Input: nums = [5,7,7,8,8,10], target = 6 Output: [-1,-1]
Example 3:
Input: nums = [], target = 0 Output: [-1,-1]
Constraints:
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums
is a non-decreasing array.-109 <= target <= 109
class Solution { public int[] searchRange(int[] nums, int target) { int first = search(nums, target, true); int last = search(nums, target, false); return new int[]{first, last}; } private int search(int[] nums, int target, boolean first) { int left = 0, right = nums.length - 1; int result = -1; while(left <= right) { int mid = left + (right - left) / 2; if(nums[mid] < target) left = mid + 1; else if(nums[mid] > target) right = mid - 1; else{ //store result result = mid; if(first) right = mid - 1; else left = mid + 1; } } return result; } }
You are given an integer mountainHeight
denoting the height of a mountain.
You are also given an integer array workerTimes
representing the work time of workers in seconds.
The workers work simultaneously to reduce the height of the mountain. For worker i
:
- To decrease the mountain's height by
x
, it takesworkerTimes[i] + workerTimes[i] * 2 + ... + workerTimes[i] * x
seconds. For example:- To reduce the height of the mountain by 1, it takes
workerTimes[i]
seconds. - To reduce the height of the mountain by 2, it takes
workerTimes[i] + workerTimes[i] * 2
seconds, and so on.
- To reduce the height of the mountain by 1, it takes
Return an integer representing the minimum number of seconds required for the workers to make the height of the mountain 0.
Example 1:
Input: mountainHeight = 4, workerTimes = [2,1,1]
Output: 3
Explanation:
One way the height of the mountain can be reduced to 0 is:
- Worker 0 reduces the height by 1, taking
workerTimes[0] = 2
seconds. - Worker 1 reduces the height by 2, taking
workerTimes[1] + workerTimes[1] * 2 = 3
seconds. - Worker 2 reduces the height by 1, taking
workerTimes[2] = 1
second.
Since they work simultaneously, the minimum time needed is max(2, 3, 1) = 3
seconds.
Example 2:
Input: mountainHeight = 10, workerTimes = [3,2,2,4]
Output: 12
Explanation:
- Worker 0 reduces the height by 2, taking
workerTimes[0] + workerTimes[0] * 2 = 9
seconds. - Worker 1 reduces the height by 3, taking
workerTimes[1] + workerTimes[1] * 2 + workerTimes[1] * 3 = 12
seconds. - Worker 2 reduces the height by 3, taking
workerTimes[2] + workerTimes[2] * 2 + workerTimes[2] * 3 = 12
seconds. - Worker 3 reduces the height by 2, taking
workerTimes[3] + workerTimes[3] * 2 = 12
seconds.
The number of seconds needed is max(9, 12, 12, 12) = 12
seconds.
Example 3:
Input: mountainHeight = 5, workerTimes = [1]
Output: 15
Explanation:
There is only one worker in this example, so the answer is workerTimes[0] + workerTimes[0] * 2 + workerTimes[0] * 3 + workerTimes[0] * 4 + workerTimes[0] * 5 = 15
.
Constraints:
1 <= mountainHeight <= 105
1 <= workerTimes.length <= 104
1 <= workerTimes[i] <= 106
class Solution { /** 关键点: 1. 二分法猜答案,猜出需要用的最短时间 2. 给定的时间,如何求出某worker可以削减的最大高度 3. 如何计算当前workerTime削减x层所需时间? workerTime + workerTime * 2 + ... + workerTime * x = workerTime * (1 + 2 + ... + x) = workerTime * n * (n + 1) / 2 */ public long minNumberOfSeconds(int mountainHeight, int[] workerTimes) { long left = 1, right = Long.MAX_VALUE; long result = 0; // 二分猜答案,猜出需要用的最短时间 while(left <= right) { long mid = left + (right - left) / 2; if(isPossible(mountainHeight, workerTimes, mid)) { result = mid; right = mid - 1; } else { left = mid + 1; } } return result; } private boolean isPossible(int mountainHeight, int[] workerTimes, long timeCost) { for(int workerTime : workerTimes) { //针对当前workderTimer和给定的timecost,计算最大的height削减 mountainHeight -= maxHeight(workerTime, timeCost); if(mountainHeight <= 0) return true; } return false; } private int maxHeight(int wt, long timeCost) { //二分法,求出可以削减的最大高度 long left = 0, right = 100000; int result = 0; while(left <= right) { long mid = left + (right - left) / 2; // 如果当前mid 耗时满足timecost,尝试扩大值 if(wt * mid * (mid + 1) / 2 <= timeCost) { result = (int)mid; left = mid + 1; } else {//否则尝试缩小值 right = mid - 1; } } return result; } }
Given a string s
and an array of strings words
, return the number of words[i]
that is a subsequence of s
.
A subsequence of a string is a new string generated from the original string with some characters (can be none) deleted without changing the relative order of the remaining characters.
- For example,
"ace"
is a subsequence of"abcde"
.
Example 1:
Input: s = "abcde", words = ["a","bb","acd","ace"] Output: 3 Explanation: There are three strings in words that are a subsequence of s: "a", "acd", "ace".
Example 2:
Input: s = "dsahjpjauf", words = ["ahjpjau","ja","ahbwzgqnuk","tnmlanowax"] Output: 2
Constraints:
1 <= s.length <= 5 * 104
1 <= words.length <= 5000
1 <= words[i].length <= 50
s
andwords[i]
consist of only lowercase English letters.
class Solution { public int numMatchingSubseq(String s, String[] words) { // 记录s中a~z出现的位置 /** 0123456789 dsahjpjauf ^ ahjpjau ^ ind=8 a:2,7 d:0 h:3 j:4,6 s:1 p:5 u:8 f:9 */ List<Integer>[] posList = new List[26]; for(int i = 0; i < 26; i++) posList[i] = new ArrayList<>(); for(int i = 0; i < s.length(); i++) { char c = s.charAt(i); posList[c - 'a'].add(i); } // 轮询所有的word逐个进行匹配 int count = 0; for(String word : words) { if(match(posList, word)) { System.out.println(word); count++; } } return count; } private boolean match(List<Integer>[] posList, String word) { int ind = -1; for(char c : word.toCharArray()) { // ind为上一个字符匹配的位置,所以我们必须找到当前字符在ind之后出现的位置 int pos = search(posList[c - 'a'], ind); if(pos == -1) return false; ind = pos + 1; } return true; } private int search(List<Integer> list, int start) { if(list.isEmpty() || list.get(list.size() - 1) < start) return -1; int left = 0, right = list.size() - 1; int result = -1; while(left <= right) { int mid = left + (right - left) / 2; if(list.get(mid) >= start) { result = list.get(mid); right = mid - 1; } else { left = mid + 1; } } return result; } }
A conveyor belt has packages that must be shipped from one port to another within days
days.
The ith
package on the conveyor belt has a weight of weights[i]
. Each day, we load the ship with packages on the conveyor belt (in the order given by weights
). We may not load more weight than the maximum weight capacity of the ship.
Return the least weight capacity of the ship that will result in all the packages on the conveyor belt being shipped within days
days.
Example 1:
Input: weights = [1,2,3,4,5,6,7,8,9,10], days = 5 Output: 15 Explanation: A ship capacity of 15 is the minimum to ship all the packages in 5 days like this: 1st day: 1, 2, 3, 4, 5 2nd day: 6, 7 3rd day: 8 4th day: 9 5th day: 10 Note that the cargo must be shipped in the order given, so using a ship of capacity 14 and splitting the packages into parts like (2, 3, 4, 5), (1, 6, 7), (8), (9), (10) is not allowed.
Example 2:
Input: weights = [3,2,2,4,1,4], days = 3 Output: 6 Explanation: A ship capacity of 6 is the minimum to ship all the packages in 3 days like this: 1st day: 3, 2 2nd day: 2, 4 3rd day: 1, 4
Example 3:
Input: weights = [1,2,3,1,1], days = 4 Output: 3 Explanation: 1st day: 1 2nd day: 2 3rd day: 3 4th day: 1, 1
Constraints:
1 <= days <= weights.length <= 5 * 104
1 <= weights[i] <= 500
class Solution { /** 关键点:顺序不能变,因此直接二分猜答案 */ public int shipWithinDays(int[] weights, int days) { int left = 0, right = 5 * 10000 * 500; int result = -1; while(left <= right) { int mid = left + (right - left) / 2; if(valid(weights, days, mid)) { result = mid; right = mid - 1; } else { left = mid + 1; } } return result; } /** 给定一个max capacity 看能否在days内全部weights送完 */ private boolean valid(int[] weights, int days, int max) { int curr = 0, count = 1; for(int w : weights) { if(w > max) return false; if(curr + w <= max) { curr += w; } else { curr = w; count++; if(count > days) return false; } } return true; } }
followup: 如果运送的顺序可以变呢?
1. 保持二分法
2. 对于给定的max capacity 使用回朔
class Solution { /** 关键点:顺序不能变,因此直接二分猜答案 */ public int shipWithinDays(int[] weights, int days) { int left = 0, right = 5 * 10000 * 500; int result = -1; while(left <= right) { int mid = left + (right - left) / 2; if(valid(weights, days, mid)) { result = mid; right = mid - 1; } else { left = mid + 1; } } return result; } private boolean valid(int[] weights, int days, int max) { return isValid(weights, new int[days], max, 0); } private boolean isValid(int[] weights, int[] days, int max, int curr) { if(curr == weights.length) return true; int w = weights[curr]; for(int i = 0; i < days.length; i++) { if(days[i] + w <= max) { days[i] += w; if(isValid(weights, days, max, curr + 1)) return true; days[i] -= w; } } return false; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】