[二分查找]

  1. 二分查找原理 

    1)找≤target的最后一个数

left = 0
right = nums.length
while (left < right) {
    nums[mid]==target return mid;
    nums[mid]>target right = mid;
    nums[mid]<target left = mid + 1
return left-1 < 0 ? -1 : left - 1;

        2)找≥target的第一个数

left = 0
right = nums.length
while (left < right) {
    nums[mid]==target return mid;
    nums[mid]>target right = mid;
    nums[mid]<target left = mid + 1
return left >= nums.length ? -1 : left;

2.利用二分查找的典型题目

1​​​​​​​​​​​​​​LCP 12. 小张刷题计划 - 力扣(LeetCode

 

基于每天完成的题目用时去计算天数

二分查找的是每天完成题目的用时

public int minTime(int[] timeint m) {

        int left = 0;

        int right = Integer.MAX_VALUE;

        while (left < right) {

            int mid = left + (right - left) / 2;

            if (checkDirection(time, mid, m)) {

                right = mid;

            } else {

                left = mid + 1;

            }

        }

        return left;

    }

    public boolean checkDirection(int[] timeint targetint m) {

        int days = 1;

        int index = 0;

        int sumTime = 0;

        int maxTime = 0;

        boolean helpler = true;

        for (int i = 0; i < time.length; i++) {

            sumTime += time[i];

            maxTime = Math.max(maxTime, time[i]);

            if (sumTime > target) {

                if (helpler) {

                    sumTime -= maxTime;

                    helpler = false;

                } else {

                    days++;

                    i--; //因为当前加上time[i]超过target,所以这个time[i]从当天剪掉,归为下一天

                    sumTime = 0;

                    maxTime = 0;

                    helpler = true;

                }

            }

        }

        return days <= m;

    }

力扣练习:

2064、2187、2226

2187. 完成旅途的最少时间 - 力扣(LeetCode)

暴力解法:依次增加时间

long[] complete;

    int sum = 0;

    public long minimumTime1(int[] timeint totalTrips) {

        complete = new long[time.length];

        long timeStamp = 0;

        while (sum < totalTrips) {

            timeStamp++;

            sum = 0;

            for (int i = 0; i < time.length; i++) {

                complete[i] = timeStamp / (long)time[i];

                sum += complete[i];

            }

        }

        return timeStamp;

    }

----暴力解法是依次增加的时间,可以利用二分查找去寻找一个最小的timeStamp----二分查找寻找左侧边界

public long minimumTime(int[] timeint totalTrips) {

        long left = 0;

        long right = getRight(time, totalTrips);

        while (left < right) {

            long mid = left + (right - left) / 2;

            if (checkYes(time, totalTrips, mid)) {

                right = mid;

            } else {

                left = mid + 1;

            }

        }

        return left;

    }

    public boolean checkYes(int[] timeint totalTripslong target) {

        // 统计在target时刻所有公交车完成的总旅途数

        long[] completeTrip = new long[time.length];

        long sum = 0;

        for (int i = 0; i < time.length; i++) {

            completeTrip[i] = target / (long)time[i];

            sum += completeTrip[i];

        }

        return sum >= totalTrips;

    }

    public long getRight(int[] timeint totalTrip) {

        Arrays.sort(time);

        // System.out.println(time[time.length - 1] * totalTrip);

        return (long)time[time.length - 1] * (long)totalTrip;

    }

2064. 分配给商店的最多商品的最小值 - 力扣(LeetCode)

public int minimizedMaximum(int nint[] quantities) {

        int left = 0;

        int right = Integer.MAX_VALUE;

        while (left < right) {

            int mid = left + (right - left) / 2;

            if (checkRight(n, quantities, mid)) {

                right = mid;

            } else {

                left = mid + 1;

            }

        }

        return left;

    }

    public boolean checkRight(int nint[] quantitiesint target) {

        // target==0,说明每个房间放0个物品,说明肯定不对,target要增加

        if (target == 0) {

            return false;

        }

        int room = 0;

        int p1 = 0// 指向的商品指针

        int[] curQuan = Arrays.copyOf(quantities, quantities.length);

        while (p1 < quantities.length) {

            if (curQuan[p1] <= target) {

                p1++;

            } else {

                curQuan[p1] -= target;

            }

            room++;

        }

        return room <= n;

    }

2226. 每个小孩最多能分到多少糖果 - 力扣(LeetCode)

public int maximumCandies(int[] candieslong k) {

        //确定查找区间

        long sum = 0;

        // 如果糖果数量<小孩人数,直接返回0

        for (int val : candies) sum += val;

        if (sum < k) return 0;

        long left = 1, right = sum;

        long ans = 0;

        

        //二分答案进行查找

        while (left <= right) {

            long mid = left + (right - left) / 2;

            if (check(candies, mid, k)) {

                ans = mid;

                left = mid + 1;

            } else {

                right = mid - 1;

            }

        }

        return (int) ans;

    }

    

    //确定方法

    boolean check(int[] candieslong limitlong k) {

        for (int val : candies) {

            if (val < limit) continue;

            else if (val == limit) k--;

            else {

                k -= val / limit;

            }

        }

        return k <= 0;

    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值