美文网首页算法
二分查找上下界

二分查找上下界

作者: Tycc | 来源:发表于2018-10-04 15:58 被阅读0次

普通的二分查找如下。要求给的数组有序。算法题里出现有序的情况时,用二分查找能将数组内查找的时间复杂度从O(N)降到O(logn)。

    int bSearch(int[] array, int k){
        if(array == null || array.length==0) //判断异常值
            return -1;
        int l = 0, r = array.length-1, mid;
        while (l<=r){ //注意等号
            mid = l+((r-l)>>1); //写成 mid = l + (r-l)/2 也可以。这样可以防止l+r溢出。
            if(array[mid]>k)
                r=mid-1; 
            else if(array[mid]<k)
                l=mid+1;
            else
                return mid;
        }
        return -1;
    }

求上下界如下。对有些算法题来说很有用。
核心思想是,要求哪一个边界,另一个边界就要把=情况也考虑进入,从另一边界压缩左右间的空间。

int lowerBound(int[] array, int k){
        if(array == null || array.length==0)
            return -1;
        int l = 0, r = array.length-1, mid;
        while(l<=r){
            mid = l + ((r-l)>>1);
            if(array[mid]>=k)
                r = mid - 1;
            else
                l = mid + 1;
        }
        if(array[l] >= k)
            return l;
        else
            return -1;
    }

    int upperBound(int[] array, int k){
        if(array == null || array.length==0)
            return -1;
        int l = 0, r = array.length-1, mid;
        while(l<=r){
            mid = l + ((r-l)>>1);
            if(array[mid]<=k)
                l = mid + 1;
            else
                r = mid - 1;
        }
        if(array[r] <= k)
            return r;
        else
            return -1;
    }

例题:

今日头条算法题 用户喜好
时间限制:3秒
空间限制:262144K
为了不断优化推荐效果,今日头条每天要存储和处理海量数据。假设有这样一种场景:我们对用户按照它们的注册时间先后来标号,对于一类文章,每个用户都有不同的喜好值,我们会想知道某一段时间内注册的用户(标号相连的一批用户)中,有多少用户对这类文章喜好值为k。因为一些特殊的原因,不会出现一个查询的用户区间完全覆盖另一个查询的用户区间(不存在L1<=L2<=R2<=R1)。
输入描述:
输入: 第1行为n代表用户的个数 第2行为n个整数,第i个代表用户标号为i的用户对某类文章的喜好度 第3行为一个正整数q代表查询的组数 第4行到第(3+q)行,每行包含3个整数l,r,k代表一组查询,即标号为l<=i<=r的用户中对这类文章喜好值为k的用户的个数。 数据范围n <= 300000,q<=300000 k是整型
输出描述:
输出:一共q行,每行一个整数代表喜好值为k的用户的个数
输入例子1:
5
1 2 3 3 5
3
1 2 1
2 4 5
3 5 3

输出例子1:
1
0
2

例子说明1:
样例解释:
有5个用户,喜好值为分别为1、2、3、3、5,
第一组询问对于标号[1,2]的用户喜好值为1的用户的个数是1
第二组询问对于标号[2,4]的用户喜好值为5的用户的个数是0
第三组询问对于标号[3,5]的用户喜好值为3的用户的个数是2

直接顺序查找会说您的程序未能在规定时间内运行结束。
解法是记录对每个k来说,用户序号出现的位置。

import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);

        HashMap<Integer, List<Integer>> like = new HashMap<>();
        int n = input.nextInt();
        int k;
        for(int i=1; i<=n; i++){
            k = input.nextInt();
            if(like.containsKey(k)){
                List<Integer> list = like.get(k);
                list.add(i);
            }
            else {
                List<Integer> list = new ArrayList<>();
                list.add(i);
                like.put(k, list);
            }
        }

        int q = input.nextInt();
        int l, r ,result = 0;
        for(int i = 0; i<q; i++){
            l=input.nextInt();
            r=input.nextInt();
            k=input.nextInt();
            result = 0;
            List<Integer> list = like.get(k);
            //这里其实用顺序查找也能ac,仅做演示。
            if(list!=null){
                Integer[] array = list.toArray(new Integer[0]);
                int start = lowerBound(array, k);
                int end = upperBound(array, k);
                if(start!=-1 && end !=-1)
                    result = end - start + 1;
            }
            System.out.println(result);
        }

    }
    static int lowerBound(Integer[] array, int k){
        if(array == null || array.length==0)
            return -1;
        int l = 0, r = array.length-1, mid;
        while(l<=r){
            mid = l + ((r-l)>>1);
            if(array[mid]>=k)
                r = mid - 1;
            else
                l = mid + 1;
        }
        if(array[l] >= k)
            return l;
        else
            return -1;
    }

    static int upperBound(Integer[] array, int k){
        if(array == null || array.length==0)
            return -1;
        int l = 0, r = array.length-1, mid;
        while(l<=r){
            mid = l + ((r-l)>>1);
            if(array[mid]<=k)
                l = mid + 1;
            else
                r = mid - 1;
        }
        if(array[r] <= k)
            return r;
        else
            return -1;
    }
}

相关文章

  • 11.二分查找的实现与特性

    11.二分查找的实现与特性 二分查找的前提 目标函数单调性(单调递增或者递减) 存在上下界(bounded) 能够...

  • linux c/c++ 面试题目整理(二)

    11、编写一个二分查找函数,下界为low,上界为high 递归法: 非递归法: 注意:二分查找算法前提是已经排好序...

  • 二分查找的一些思考

    [toc] 二分查找 二分查找中常见的疑惑 二分写法通常有很多种,有的时候自己在写的时候往往会纠结与上下界、开闭区...

  • 二分查找

    二分查找的特点: Sorted (单调递增或者递减) Bound (存在上下界) Accessible by in...

  • leetcode-Array篇easy难度之求指定偏移量元素数量

    关键词 绝对值,二分查找,上下界,TreeSet 题目描述 https://leetcode.com/proble...

  • 二分查找上下界

    普通的二分查找如下。要求给的数组有序。算法题里出现有序的情况时,用二分查找能将数组内查找的时间复杂度从O(N)降到...

  • Java的二分查找及上下界

    普通的二分查找,利用中间数比较,将上界下标或者下界下标减1或者加1,针对查找某个数是否存在的情况,或者是某个有序数...

  • 二分查找 Binary Search Algorithm

    二分查找的前提 目标函数单调性(单调递增或递减,支队有序数组有效) 存在上下界(bounded) 能够通过索引访问...

  • 二分查找(上):如何用最省内存的方式实现快速查找功能?

    二分查找(上):如何用最省内存的方式实现快速查找功能? 注意,二分查找(也叫折半查找)是针对有序数据集合的查找算法...

  • python二分查找算法

    文章概述 二分查找法介绍 简单查找与二分查找对比 二分查找  二分查找算法主要思想:在有序列表中查找指定元素,先从...

网友评论

    本文标题:二分查找上下界

    本文链接:https://www.haomeiwen.com/subject/unpxaftx.html