ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

二分查找的分析与应用

2022-02-02 00:01:25  阅读:152  来源: 互联网

标签:二分 right tar int sums mid 查找 应用 left


二分查找的分析与应用

看leetcode一道题

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-size-subarray-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

该题可以使用前缀和+二分查找解决,时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)。
答案:

public class PrefixSum {
    public static void main(String[] args) {
        //给定一个正整数数列
        int[] nums=new int[]{1,1,1,1,1,1,1,1};
        PrefixSum prefixSum = new PrefixSum();
        System.out.println(prefixSum.minSubArrayLen(nums,11));
    }
    public int  minSubArrayLen(int[] nums, int target){
        int[] sums=Sum(nums);
        int sumsMin=Integer.MAX_VALUE;
        for(int i=0;i<sums.length;i++){
            int tar=sums[i]+target;
            int boundary=binarySearch(sums,tar);
            if(boundary>0) {
                sumsMin = Math.min(sumsMin, boundary - i);
            }
        }

       return  sumsMin==Integer.MAX_VALUE?0:sumsMin;
    }
    //  求前缀和, 该前缀和是升序的
    public int[] Sum(int[] nums){
        int sum=0;
        int[] sums=new int[nums.length+1];
        sums[0]=0;
        //使用一次遍历求出数组nums的前缀和其中sums[i]表示nums[0]到nums[i-1]的和
        for(int i=0;i<nums.length;i++){
            sum+=nums[i];
            sums[i+1]=sum;
        }
        return sums;
    }
    //前提保证数组是升序的
    //使用二分查找前缀和中第一个>=sums[i]+target的元素
    public int binarySearch(int[] sums,int tar){
        int left=0;
        int right=sums.length-1;
        if(sums[right]>=tar) {
            while (left < right) {
                int mid = left + (right - left) / 2;//最终的mid总是等于left
                if (sums[mid] < tar) {//最终该判断为真,left==right,返回结果
                    left = mid + 1;
                } else {
                    right = mid;//将>=target的下标放在右边界,结束时该边界就是结果
                }
            }
            return left;
        }
        return -1;
    }
}

二分查找

1. 1. 1. 二分查找的前提:要求数组为有序数组,一般为升序;数组中允许有重复元素;
2. 2. 2. 二分法有三个指针,分别是: l e f t left left、 r i g h t right right、 m i d mid mid,顾名思义;
3. 3. 3. 最后一次循环, l e f t + 1 = = r i g h t left+1==right left+1==right; m i d = = l e f t mid==left mid==left; r i g h t right right一直捕获符合条件的元素;最终返回的其实是 r i g h t right right;
2. 2. 2. 实现二分查找代码:

public int binarySearch(int[] sums,int tar){
        int left=0;
        int right=sums.length-1;
        if(sums[right]>=tar) {
            while (left < right) {
                int mid = left + (right - left) / 2;//最终的mid总是等于left
                if (sums[mid] < tar) {//最终该判断为真,left==right,返回结果
                    left = mid + 1;
                } else {
                    right = mid;//将>=target的下标放在右边界,结束时该边界就是结果
                }
            }
            return left;
        }
        return -1;
    }

上面代码可以查找给定数组 s u m s sums sums中第一个 > = >= >=给定数 t a r tar tar的元素,并返回数组下标,当数组中没有 > = >= >=给定数 t a r tar tar的元素时返回-1;

源码分析

1. 1. 1. 源码比上面代码多了一个以取反的形式返回一个数组中不存在的元素的位置,该位置处于第一个 > = >= >=给定数 t a r tar tar的元素的相邻左边;

private static int binarySearch0(int[] a, int fromIndex, int toIndex,
                                     int key) {
        int low = fromIndex;
        int high = toIndex - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            int midVal = a[mid];

            if (midVal < key)
                low = mid + 1;
            else if (midVal > key)
                high = mid - 1;
            else
                return mid; // key found
        }
        return -(low + 1);  // key not found.
    }

如果数组中不存在目标元素,则返回第一个>目标元素的元素位置,这个位置是以反数的形式返回:-(low+1)取反后为low.

感想:感觉leetcode这道题给定的数组的元素可以是自然数,也就是说可以有为0的元素

标签:二分,right,tar,int,sums,mid,查找,应用,left
来源: https://blog.csdn.net/weixin_43716907/article/details/122766739

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有