二分法

2 篇文章 0 订阅
1 篇文章 0 订阅

使用二分法可将查找的时间复杂度从o(n)降低至o(logn)。使用二分法要特别注意搜索的区间是否有遗漏,大部分的出错点都在于此。二分查找常用于查找某个数或是查找某个边界

题眼:有序

查找某个数的框架模板:

例题1:LeetCode 704.二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1
示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为4

示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回-1
int binarySearch(int[] nums, int target){
    if(nums == null || nums.length == 0){
        return -1;
    }
    int left = 0, right = nums.length - 1;
    while(left <= right){
        int mid = left + (right - left) / 2;//这样写可以避免left+right过大而溢出
        if(nums[mid] == target){
            return mid;
        }
        else if(nums[mid] < target){
            left = mid + 1;
        }
        else{
            right = mid - 1;
        }
    }
    return -1;
}

例题2:LeetCode 441.排列硬币

你总共有 n 枚硬币,你需要将它们摆成一个阶梯形状,第 k 行就必须正好有 k 枚硬币。给定一个数字 n,找出可形成完整阶梯行的总行数。n 是一个非负整数,并且在32位有符号整型的范围内。

示例 1:

n = 5

硬币可排列成以下几行:
¤
¤ ¤
¤ ¤

因为第三行不完整,所以返回2.

示例 2:

n = 8

硬币可排列成以下几行:
¤
¤ ¤
¤ ¤ ¤
¤ ¤

因为第四行不完整,所以返回3.

class Solution {
    public int arrangeCoins(int n) {
        int left = 0, right = n;
        while(left<=right){
            long mid = left  + (right - left) / 2;
            long sum = mid * (mid+1) / 2; //公式需要推导一下
            if(sum == n){
                return (int)mid;
            }else if(sum < n){
                left = (int)mid + 1;
            }
            else if(sum > n){
                right = (int)mid - 1;
            }
        }
        return right;
    }
}

 查找某个边界的框架模板:

例题3:LeetCode 278.第一个错误的版本

你是产品经理,目前正在带领一个团队开发新的产品。不幸的是,你的产品的最新版本没有通过质量检测。由于每个版本都是基于之前的版本开发的,所以错误的版本之后的所有版本都是错的。

假设你有 n 个版本 [1, 2, ..., n],你想找出导致之后所有版本出错的第一个错误的版本。

你可以通过调用 bool isBadVersion(version) 接口来判断版本号 version 是否在单元测试中出错。实现一个函数来查找第一个错误的版本。你应该尽量减少对调用 API 的次数。

示例:

给定 n = 5,并且 version = 4 是第一个错误的版本。

调用 isBadVersion(3) -> false
调用 isBadVersion(5) -> true
调用 isBadVersion(4) -> true

所以,4 是第一个错误的版本。

public class Solution extends VersionControl {
    public int firstBadVersion(int n) {
        int left = 1, right = n;
        while(left <= right){
            int mid = left + (right - left) / 2;
            boolean temp = isBadVersion(mid);
            if(temp == false){
                left = mid + 1;
            }else if(temp == true){
                right = mid - 1;//逼近左边界
            }
        }
        return left;
    }
}

例题4:LeetCode 875.爱吃香蕉的珂珂

珂珂喜欢吃香蕉。这里有 N 堆香蕉,第 i 堆中有 piles[i] 根香蕉。警卫已经离开了,将在 H 小时后回来。

珂珂可以决定她吃香蕉的速度 K (单位:根/小时)。每个小时,她将会选择一堆香蕉,从中吃掉 K 根。如果这堆香蕉少于 K 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉。  

珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。

返回她可以在 H 小时内吃掉所有香蕉的最小速度 K(K 为整数)。

示例 1:

输入: piles = [3,6,7,11], H = 8
输出: 4

示例 2:

输入: piles = [30,11,23,4,20], H = 5
输出: 30

示例 3:

输入: piles = [30,11,23,4,20], H = 6
输出: 23

class Solution {
    public int minEatingSpeed(int[] piles, int H) {
        int left = 1, right = getMax(piles);
        while(left <= right){
            int mid = left+ (right - left) / 2;
            boolean temp = canFinish(mid, piles, H);
            if(temp == true){
                right = mid - 1;
            }else if(temp == false){
                left = mid + 1;
            }
        }
        return left;
    }
    private int getMax(int[] piles){
        int max = 0;
        for(int n: piles){
            max = Math.max(max, n);
        }
        return max;
    }
    private boolean canFinish(int speed, int[] piles, int H){
        int h = H;
        for(int i = 0; i < piles.length; i++){
            if(piles[i]%speed == 0){
                h = h - (piles[i]/speed); 
            }else{
                h = h - (piles[i]/speed) - 1;
            }
            if(h<0){
                return false;
            }
        }
        return true;
    }
}

例题5:LeetCode 1011.在D天内送达包裹的能力

传送带上的包裹必须在 D 天内从一个港口运送到另一个港口。

传送带上的第 i 个包裹的重量为 weights[i]。每一天,我们都会按给出重量的顺序往传送带上装载包裹。我们装载的重量不会超过船的最大运载重量。

返回能在 D 天内将传送带上的所有包裹送达的船的最低运载能力。

示例 1:

输入:weights = [1,2,3,4,5,6,7,8,9,10], D = 5
输出:15
解释:
船舶最低载重 15 就能够在 5 天内送达所有包裹,如下所示:
第 1 天:1, 2, 3, 4, 5
第 2 天:6, 7
第 3 天:8
第 4 天:9
第 5 天:10

请注意,货物必须按照给定的顺序装运,因此使用载重能力为 14 的船舶并将包装分成 (2, 3, 4, 5), (1, 6, 7), (8), (9), (10) 是不允许的。

示例 2:

输入:weights = [3,2,2,4,1,4], D = 3
输出:6
解释:
船舶最低载重 6 就能够在 3 天内送达所有包裹,如下所示:
第 1 天:3, 2
第 2 天:2, 4
第 3 天:1, 4

示例 3:

输入:weights = [1,2,3,1,1], D = 4
输出:3
解释:
第 1 天:1
第 2 天:2
第 3 天:3
第 4 天:1, 1

class Solution {
    public int shipWithinDays(int[] weights, int D) {
        int left = getMax(weights), right = sum(weights);
        while(left <= right){
            int mid = left + (right - left) / 2;
            boolean temp = canFinish(mid, weights, D);
            if(temp == true){
                right = mid - 1;
            }else if(temp == false){
                left = mid + 1;
            }
        }
        return left;
    }
    private int getMax(int[] weights){
        int max = 0;
        for(int n: weights){
            max = Math.max(max, n);
        }
        return max;
    }
    private int sum(int[] weights){
        int sum = 0;
        for(int n: weights){
            sum = sum + n;
        }
        return sum;
    }
    private boolean canFinish(int minWeight, int[] weights, int D){
        int d = D;
        int tempWeight = 0;
        for(int i = 0; i < weights.length; i++){
            if(tempWeight + weights[i] <= minWeight){
                tempWeight = tempWeight + weights[i];
            }else{
                d = d - 1;
                tempWeight = weights[i];
            }
            if(d < 1){
                return false;
            }
        }
        return true;
    }
}

例题6:LeetCode 1482.制作m束花所需要的最少天数

给你一个整数数组 bloomDay,以及两个整数 m 和 k 。现需要制作 m 束花。制作花束时,需要使用花园中相邻的 k 朵花 。花园中有 n 朵花,第 i 朵花会在 bloomDay[i] 时盛开,恰好可以用于一束花中。请你返回从花园中摘 m 束花需要等待的最少的天数。如果不能摘到 m 束花则返回 -1 。

示例 1:

输入:bloomDay = [1,10,3,10,2], m = 3, k = 1
输出:3
解释:让我们一起观察这三天的花开过程,x 表示花开,而 _ 表示花还未开。
现在需要制作 3 束花,每束只需要 1 朵。
1 天后:[x, _, _, _, _]   // 只能制作 1 束花
2 天后:[x, _, _, _, x]   // 只能制作 2 束花
3 天后:[x, _, x, _, x]   // 可以制作 3 束花,答案为 3

示例 2:

输入:bloomDay = [1,10,3,10,2], m = 3, k = 2
输出:-1
解释:要制作 3 束花,每束需要 2 朵花,也就是一共需要 6 朵花。而花园中只有 5 朵花,无法满足制作要求,返回 -1 。

示例 3:

输入:bloomDay = [7,7,7,7,12,7,7], m = 2, k = 3
输出:12
解释:要制作 2 束花,每束需要 3 朵。
花园在 7 天后和 12 天后的情况如下:
7 天后:[x, x, x, x, _, x, x]
可以用前 3 朵盛开的花制作第一束花。但不能使用后 3 朵盛开的花,因为它们不相邻。
12 天后:[x, x, x, x, x, x, x]
显然,我们可以用不同的方式制作两束花。

示例 4:

输入:bloomDay = [1000000000,1000000000], m = 1, k = 1
输出:1000000000
解释:需要等 1000000000 天才能采到花来制作花束

示例 5:

输入:bloomDay = [1,10,2,9,3,8,4,7,5,6], m = 4, k = 2
输出:9

class Solution {
    public int minDays(int[] bloomDay, int m, int k) {
        int left = 1, right = getMax(bloomDay);
        int result = -1;
        while(left <= right){
            int mid = left + (right - left) / 2;
            boolean temp = canFinish(mid, bloomDay, m, k);
            if(temp == true){
                right = mid - 1;
            }else if(temp == false){
                left = mid + 1;
            }
        }
        if(left <= getMax(bloomDay)){
            result = left;
        }
        return result;
    }
    private boolean canFinish(int mid, int[] bloomDay, int m, int k){
        int slow = 0, fast = 0;
        while(fast != bloomDay.length){
            if(bloomDay[fast] - mid <= 0){//摘够k朵
                if(fast - slow + 1 == k){
                    m = m - 1;
                    slow = fast+1;
                }
            }
            if(bloomDay[fast] - mid > 0){//遇到没开的花
                slow = fast+1;
            }
            fast = fast + 1;
            if(m == 0){
                return true;
            }
        }
        return false;
    }
    private int getMax(int[] nums){
        int max = 0;
        for(int item: nums){
            max = Math.max(item, max);
        }
        return max;
    }
}

例题7:LeetCode 410.分割数组的最大值

给定一个非负整数数组和一个整数 m,你需要将这个数组分成 m 个非空的连续子数组。设计一个算法使得这 m 个子数组各自和的最大值最小。数组长度 n 满足: 1 ≤ n ≤ 1000, 1 ≤ m ≤ min(50, n)

示例:

输入:
nums = [7,2,5,10,8]
m = 2

输出:
18

解释:
一共有四种方法将nums分割为2个子数组。其中最好的方式是将其分为[7,2,5] 和 [10,8],因为此时这两个子数组各自的和的最大值为18,在所有情况中最小。

class Solution {
    public int splitArray(int[] nums, int m) {
        int left = getMax(nums), right = sum(nums);
        while(left <= right){
            int mid = left + (right - left) / 2;
            System.out.println(left+"_"+right+"_"+mid);
            boolean temp = canFinish(mid, nums, m);
            if(temp == true){
                right = mid - 1;
            }else if(temp == false){
                left = mid + 1;
            }
        }
        return left;
    }
    private boolean canFinish(int mid, int[] nums, int m){
        int temp = mid;
        for(int i = 0; i < nums.length; i++){
            if(temp - nums[i] >= 0){
                temp = temp - nums[i];
            }else if(temp - nums[i] < 0){
                if(m > 1){
                    temp = mid - nums[i];
                    m = m - 1;
                }else{
                    return false;
                }
            }
        }
        return true;
    }
    private int getMax(int[] nums){
        int max = 0;
        for(int item: nums){
            max = Math.max(item, max);
        }
        return max;
    }
    private int sum(int[] nums){
        int result = 0;
        for(int item: nums){
            result = result + item;
        }
        return result;
    }
}

例题8:LeetCode LCP 12. 小张刷题计划

为了提高自己的代码能力,小张制定了 LeetCode 刷题计划,他选中了 LeetCode 题库中的 n 道题,编号从 0 到 n-1,并计划在 m 天内按照题目编号顺序刷完所有的题目(注意,小张不能用多天完成同一题)。在小张刷题计划中,小张需要用 time[i] 的时间完成编号 i 的题目。此外,小张还可以使用场外求助功能,通过询问他的好朋友小杨题目的解法,可以省去该题的做题时间。为了防止“小张刷题计划”变成“小杨刷题计划”,小张每天最多使用一次求助。我们定义 m 天中做题时间最多的一天耗时为 T(小杨完成的题目不计入做题总时间)。请你帮小张求出最小的 T是多少。

示例 1:

    输入:time = [1,2,3,3], m = 2

    输出:3

    解释:第一天小张完成前三题,其中第三题找小杨帮忙;第二天完成第四题,并且找小杨帮忙。这样做题时间最多的一天花费了 3 的时间,并且这个值是最小的。

示例 2:

    输入:time = [999,999,999], m = 4

    输出:0

    解释:在前三天中,小张每天求助小杨一次,这样他可以在三天内完成所有的题目并不花任何时间。

class Solution {
    public int minTime(int[] time, int m) {
        if(m >= time.length){
            return 0;
        }
        int left = 0, right = sum(time);
        while(left <= right){
            int mid = left + (right - left) / 2;
            boolean temp = canFinish(mid, time, m);
            if(temp == true){
                right = mid - 1;
            }else if(temp == false){
                left = mid + 1;
            }
        }
        return left;
    }
    private int sum(int[] time){
        int s = 0;
        for(int i = 0; i < time.length; i++){
            s = s + time[i];
        }
        return s;
    }
    private boolean canFinish(int mid, int[] time, int m){
        int max = 0, temp = mid;
        for(int i = 0; i < time.length; i++){
            max = Math.max(time[i], max);
            if(temp - time[i] + max >=0){
                temp = temp - time[i];
            }else if(temp - time[i] + max < 0){
                if(m > 1){
                    temp = mid - time[i];
                    max = time[i];
                    m = m - 1;
                }else{
                    return false;
                }
            }
        }
        return true;
    }
}

不难发现,例题3,例题4,例题5,例题6, 例题7,例题8的核心框架其实都是一样的,都是例题3的代码,例题4,例题5,例题6,例题7,例题8只是赋予了不同的所要逼近的边界条件。

例题9:LeetCode 34.在排序数组中查找元素的第一个和最后一个位置

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。限制时间复杂度为 O(log n) 。

示例 1:

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

示例 2:

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

示例 3:

输入:nums = [], target = 0
输出:[-1,-1]

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(nums[mid] == target){
                if(nums[left] != target){
                    left = left + 1;//逼近左边界
                }
                if(nums[right] != target){
                    right = right - 1;//逼近右边界
                }
                if(nums[right] == target && nums[left] == target){
                    break;
                }
            }else if(nums[mid] > target){
                right = mid - 1;

            }else if (nums[mid] < target){
                left = mid + 1;
            }
        }
        if(left > right){
            return new int[]{-1, -1};
        }else{
            return new int[]{left, right};
        }
    }
}

前面提到,使用二分法的一个前提是数组是有序的,如果数组不是严格有序,也可以利用局部有序的特点,使用二分法。如LeetCode上的排序旋转数组系列:

例题10:LeetCode 153.寻找旋转排序数组中的最小值

假设按照升序排序的数组在预先未知的某个点上进行了旋转。例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] 。请找出其中最小的元素。限制时间复杂度为 O(log n) 。

示例 1:

输入:nums = [3,4,5,1,2]
输出:1

示例 2:

输入:nums = [4,5,6,7,0,1,2]
输出:0

示例 3:

输入:nums = [1]
输出:1

旋转排序数组可以看作是两个升序数组拼接在一起,且第二个升序数组的起始值小于第一个升序数组的结束值,所以可以利用这一特点寻找分界点:

class Solution {
    public int findMin(int[] nums) {
        int n = nums.length;
        if(n == 1){
            return nums[0];
        }else if(nums.length>1){
            if(nums[0] < nums[n - 1]){
                return nums[0];
            }
        }
        int left = 0, right = n - 1;
        int result = 0;
        while(left <= right){
            int mid = left + (right-left)/2;
            if(nums[mid] > nums[mid+1]){//下一元素比当前元素小,找到分界点
                result = nums[mid+1];
                break;  
            }else if(nums[left] > nums[mid]){//左边不是严格有序,分界点在左边
                right = mid;    //特别注意这里是right = mid 而不是 right = mid + 1,因为终止条件实际上要搜索两个数(且为中间的和中间偏右的),所以当右边界收缩时,需要少收缩1个
            }else if(nums[left] < nums[mid]){//右边不是严格有序,分界点在右边
                left = mid + 1;
            }
        }
        return result;
    }
}

例题11:LeetCode: 154.寻找旋转排序数组中的最小值II

假设按照升序排序的数组在预先未知的某个点上进行了旋转。( 例如,数组 [0,1,2,4,5,6,7] 可能变为 [4,5,6,7,0,1,2] )。请找出其中最小的元素。注意数组中可能存在重复的元素。限制时间复杂度为 O(log n) 。

示例 1:

输入: [1,3,5]
输出: 1

示例 2:

输入: [2,2,2,0,1]
输出: 0

class Solution {
    public int findMin(int[] nums) {
        int left = 0, right = nums.length - 1;
        while(left <= right){
            if(nums[left] < nums[right]){//在当前搜索区间里,左边元素小于右边元素,说明是升序的,左边即为最小
                return nums[left];
            }
            int mid = left + (right-left)/2;
            if(nums[left] > nums[mid]){//在当前搜索区间里,左边元素大于中间元素,说明在当前搜索区间里,左边到中间这一段不是严格有序的,应当在这一段里查找
                right = mid;
            }else if(nums[left] < nums[mid]){//在当前搜索区间里,左边元素小于中间元素,说明在当前搜索区间里,中间到右边这一段不是严格有序的,应当在这一段里查找
                left = mid; 
            }else if(nums[left] == nums[mid]){//在当前搜索区间里,左边元素等于中间元素,说明在当前搜索区间里,中间的和左边的相等,可以成为左边元素的替代,搜索区间左边可以收缩一步
                left = left + 1;
            }
        }
        return nums[right];
    }
}

例题12:LeetCode 33.搜索旋转排序数组

升序排列的整数数组 nums 在预先未知的某个点上进行了旋转(例如, [0,1,2,4,5,6,7] 经旋转后可能变为 [4,5,6,7,0,1,2] )。

请你在数组中搜索 target ,如果数组中存在这个目标值,则返回它的索引,否则返回 -1 。限制时间复杂度为 O(log n) 。

示例 1:

输入:nums = [4,5,6,7,0,1,2], target = 0
输出:4

示例 2:

输入:nums = [4,5,6,7,0,1,2], target = 3
输出:-1

示例 3:

输入:nums = [1], target = 0
输出:-1

class Solution {
    public int search(int[] nums, int target) {
        int n = nums.length;
        if(n == 1){
            if(nums[0] == target){
                return 0;
            }else{
                return -1;
            }
        }
        int result = -1, xuanzhuan=0, left, right;
        if(nums[0] < nums[n-1]){
            xuanzhuan = 0;
        }
        else{
            left = 0;
            right = n - 1;
            while(left <= right){
                int mid = left + (right - left) / 2;
                if(nums[mid] > nums[mid+1]){
                    xuanzhuan = mid+1;
                    break;
                }else if(nums[left] > nums[mid]){
                    right = mid;
                }else if(nums[left] < nums[mid]){
                    left = mid;
                }
            }
        }
        if(target <= nums[n-1]){
            left = xuanzhuan;
            right = n-1;
        }else{
            left = 0;
            right = xuanzhuan - 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 if(nums[mid] == target){
                result = mid;
                break;
            }
        }
        return result;
    }
}

例题13:LeetCode 852.山脉数组的峰顶索引

我们把符合下列属性的数组 A 称作山脉:

    A.length >= 3
    存在 0 < i < A.length - 1 使得A[0] < A[1] < ... A[i-1] < A[i] > A[i+1] > ... > A[A.length - 1]

给定一个确定为山脉的数组,返回任何满足 A[0] < A[1] < ... A[i-1] < A[i] > A[i+1] > ... > A[A.length - 1] 的 i 的值。

示例 1:

输入:[0,1,0]
输出:1

示例 2:

输入:[0,2,1,0]
输出:1

class Solution {
    public int peakIndexInMountainArray(int[] arr) {
        int left = 0, right = arr.length-1;
        while(left <= right){
            int mid = left + (right - left) / 2;
            System.out.println(left+"_"+mid+"_"+right);
            if(arr[mid] > arr[mid+1] && arr[mid] > arr[mid-1]){//先比较mid和mid+1,因为mid+1不会越界
                return mid;
            }else if(arr[mid] < arr[mid+1]){//先比较mid和mid+1,因为mid+1不会越界
                left = mid + 1;
            }else if(arr[mid] < arr[mid-1]){
                right = mid - 1;
            }
        }
        return -1;
    }
}

例题14: LeetCode 1095.山脉数组中查找目标值

(这是一个 交互式问题 )

给你一个 山脉数组 mountainArr,请你返回能够使得 mountainArr.get(index) 等于 target 最小 的下标 index 值。如果不存在这样的下标 index,就请返回 -1。

何为山脉数组?如果数组 A 是一个山脉数组的话,那它满足如下条件:

     A.length >= 3
    存在 0 < i < A.length - 1 使得A[0] < A[1] < ... A[i-1] < A[i] > A[i+1] > ... > A[A.length - 1]

你将 不能直接访问该山脉数组,必须通过 MountainArray 接口来获取数据:

    MountainArray.get(k) - 会返回数组中索引为k 的元素(下标从 0 开始)
    MountainArray.length() - 会返回该数组的长度

注意:

对 MountainArray.get 发起超过 100 次调用的提交将被视为错误答案。此外,任何试图规避判题系统的解决方案都将会导致比赛资格被取消。

示例 1:

输入:array = [1,2,3,4,5,3,1], target = 3
输出:2
解释:3 在数组中出现了两次,下标分别为 2 和 5,我们返回最小的下标 2。

示例 2:

输入:array = [0,1,2,4,2,1], target = 3
输出:-1
解释:3 在数组中没有出现,返回 -1。

class Solution {
    public int findInMountainArray(int target, MountainArray mountainArr) {
        int left = 0, right = mountainArr.length() - 1;
        int peekIndex = 0;
        while(left <= right){
            int mid = left + (right - left) / 2;
            int tempMid = mountainArr.get(mid);
            int tempMidAfter = mountainArr.get(mid+1);
            if(tempMid>tempMidAfter && tempMid>mountainArr.get(mid-1)){
                peekIndex = mid;
                break;
            }else if(tempMid < tempMidAfter){
                left = mid + 1;
            }else if(tempMid < mountainArr.get(mid-1)){
                right = mid - 1;
            }
        }
        if(target == mountainArr.get(peekIndex)){
            return peekIndex;
        }
        left = 0;
        right = peekIndex;
        while(left <= right){
            int mid = left + (right - left)/2;
            int tempMid = mountainArr.get(mid);
            if(tempMid == target){
                return mid;
            }else if(tempMid < target){
                left = mid + 1;
            }else if(tempMid > target){
                right = mid - 1;
            }
        }
        left = peekIndex;
        right = mountainArr.length() - 1;
        while(left <= right){
            int mid = left + (right - left)/2;
            int tempMid = mountainArr.get(mid);
            if(tempMid == target){
                return mid;
            }else if(tempMid < target){
                right = mid - 1;
            }else if(tempMid > target){
                left = mid + 1;
            }
        }
        return -1;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值