首页 > 试题广场 >

找出指定数在数组中的范围

[编程题]找出指定数在数组中的范围
  • 热度指数:770 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
输入一个排好序的整数数组,找到指定目标数的开始和结束位置。如果指定的数字不在数组中,则输出 [-1,-1]。例如,输入数组为[5, 7, 7, 8, 8, 10], 目标数为8, 输出[3, 4].本题会人工判题,要求时间复杂度O(logn)

输入描述:
输入数据包括两行:
第一行两个整数n(1 ≤ n ≤ 10 ^ 5),和需要查找的数target
第二行n个整数,范围均在32位整数内,以空格分隔


输出描述:
输出格式为[begin,end],如果不存在就输出[-1,-1]
示例1

输入

6 8 5 7 7 8 8 10

输出

3 4


  1. 因为题目要求时间复杂度是O(logn),故不能用简单的遍历方式查找,需要使用二分查找的方式。注意:这里在用二分查找法找到目标数字后,不能使用从该位置逐一往前或往后判断值是否仍然是目标数的“线性探测”方法做,因为可能会有以下一种情况:输入数组的所有元素值都是目标数,这样的话用二分+线性探测的方式的复杂度是O(n)。
  2. 这道题主要考察的点是二分的使用、是否对边界情况考虑周全。
  3. 以下是java实现的代码,有详细注释(所以看着好像很长,但原理很简单)


import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int target = scanner.nextInt();
        scanner.nextLine();
        int[] arr = new int[n];
        for (int i = 0; i < n; i++) {
            arr[i] = scanner.nextInt();
        }
        // begin和end分别为数组的起始和结束位置
        int begin = 0;
        int end = n - 1;
        // beginFoundLocation记录找到的目标值第一次出现的地方
        int beginFoundLocation = -1;
        // endFoundLocation 记录找到的目标值最后一次出现的地方
        int endFoundLocation = -1;
        endFoundLocation = findLastLocation(begin, end, arr, target);
        beginFoundLocation = findFirstLocation(begin, end, arr, target);
        System.out.println("[" + beginFoundLocation + "," + endFoundLocation + "]");
    }
    // 在arr数组的begin到end的范围内,寻找target第一次出现的位置
    public static int findFirstLocation(int begin, int end, int[] arr, int target) {
        // 记录中间点的位置及其值
        int middle = 0;
        int middleValue = arr[0];
        while (begin <= end) {
            middle = begin + (end - begin) / 2;
            middleValue = arr[middle];
            /*    
             * 二分查找:当中间位置点的值比target要小的时候就将寻找的起始位置(begin)设置为中间位置的下一个位置,
             * 当中间位置点的值比target要大的时候就将寻找的终止位置(end)设为中间位置的下一个位置 */
            /*
             * 注意:当中间位置的点的值正好是target的时候,需要看该位置的前一个位置点的值是否也为target,这就分为以下
             * 三种情况
             * 1.可能此时中间位置已经是0,也就是指向了数组的
             * 第一个元素,它没有前一个位置点,说明target第一次出现的位置就是0
             * 2.中间位置不是0,而且中间位置的前一个位置的值也是target,则继续用二分法在前面查找target
             * (注:这里不能用线性探测的方法,因为当输入数组元素值全部正好是target的时候,就成了遍历整个数组前半段,
             * 同理找最后target出现的位置也不能用线性探测法)。
             * 3.中间位置不是0,而且中间位置的前一个位置的值不是target,则正好该中间位置就是target第一次出现的位置,
             * 返回就好了。
             */
            if (middleValue < target) {
                begin = middle + 1;
            } else if (middleValue > target) {
                end = end - 1;
            } else if (middle > 0 && arr[middle - 1] == target) {
                end = middle - 1;
            } else if (middle > 0 && arr[middle - 1] != target) {
                return middle;
            } else if (middle == 0) {// 这里需要判定下,因为会有begin=end=0的情况,会死循环。
                return 0;
            }
        }
        // 当循环条件不满足的时候,可能是找到了target第一次出现的位置,也可能是target根本不在数组中
        if (arr[middle] != target) {
            return -1;
        } else {
            return middle;
        }
    }
    // 寻找target最后出现的位置,具体原理和寻找最初出现的位置相似
    public static int findLastLocation(int begin, int end, int[] arr, int target) {
        int middle = 0;
        int middleValue = arr[0];
        int lastArr = arr.length - 1;
        while (begin <= end) {
            middle = begin + (end - begin) / 2;
            middleValue = arr[middle];
            if (middleValue < target) {
                begin = middle + 1;
            } else if (middleValue > target) {
                end = end - 1;
            } else if (middle < lastArr && arr[middle + 1] == target) {
                begin = middle + 1;
            } else if (middle < lastArr && arr[middle + 1] != target) {
                return middle;
            } else if (middle == lastArr) {// 同样是为了防止死循环,需要判断下
                return lastArr;
            }
        }
        if (arr[middle] != target) {
            return -1;
        } else {
            return middle;
        }
    }
}

编辑于 2017-09-29 15:40:58 回复(0)
#include <iostream>

using namespace std;
int a[100001];
int main(){
    int n,tar;
    cin>>n>>tar;
    for (int i=0;i<n;i++) cin>>a[i];
    int l=0,r=n-1;
    
   
    while(l<r){
        int mid=l+r>>1;
        if(a[mid]>=tar) r=mid;
        else l=mid+1;
    }
    if (a[l]!=tar) cout<<"[-1,-1]"<<endl;
    else{
    cout<<'['<<l<<',';
    
    int l=0,r=n-1;
    while(l<r){ // 注意边界问题
        int mid=l+r+1>>1;
        if(a[mid]<=tar) l=mid;
        else r=mid-1
    }
    cout<<l<<']'<<endl;
    }
    return 0;
}
发表于 2022-08-02 16:32:16 回复(0)
n,num = map(int,input().split())
l = list(map(int,input().split()))
lst = []
for i in range(n):
    if l[i] == num:
        lst.append(i)

if len(lst) == 0:
    print('[-1,-1]')
else:
    print('[' + str(lst[0])+ ',' + str(lst[-1]) + ']')

发表于 2022-06-07 19:42:43 回复(0)

与归并排序算法有异曲同工之处

#include
using namespace std;
const int MAXN=1e5;
//int ans[MAXN];
int arr[MAXN];
int a=MAXN;
int b=-1;
void partition(int target,int left,int right)
{
    //如果是只剩下一个元素就不需要再进行分割了
    int mid=left+(right-left)/2;
    if(arr[mid]==target)
    {
       if(mid<a)
       {
           a=mid;
       }

        if(mid>b)
            b=mid;
    }
    if(left==right)
    {
        return ;
    }

        partition(target,left,mid);
        partition(target,mid+1,right);

    return;
}
int main()
{
    int n,target;

    cin>>n>>target;

    for(int i=0;i<n;i++)
    {
        cin>>arr[i];
    }

     partition(target,0,n-1);

     if(a==MAXN)
    {
        a=-1;
    }
    cout<<'['<<a<<','<<b<<']'<<endl;

    return 0;

}
发表于 2022-04-16 21:26:00 回复(0)
import java.util.Scanner;

public class Test{
public static void main(String[] args){
    Scanner scanner = new Scanner(System.in);
    String a = scanner.nextLine();
    a = a.substring(1,a.length()-1);
    String[] b = a.split(",");
    int target = scanner.nextInt();
    int[] c = new int[b.length];
    for(int i=0;i<b.length;i++) {
        c[i] = Integer.valueOf(b[i]);
    }
    first(target,c);
}

static void first(int target,int[] c) {
    int n = c.length;
    int start = 0,end = n-1;
    int first=0,last=0;
    int mid = (n-1)/2,midvalue = c[mid];
    while(start<end) {
        if(target<midvalue) {
            end = mid-1;
            mid = end/2;
            midvalue = c[mid];
        }else if(target>midvalue) {
            start = mid+1;
            mid = (end + start)/2;
            midvalue = c[mid];
        }else {
            first = mid; last = mid;
            for(int i=mid;i>=start;i--) {
                if(c[i-1]!=target) {
                    first = i;
                    start = end;
                    break;
                }
            }
            for(int i=mid;i<=end;i++) {
                if(c[i+1]!=target) {
                    last = i;
                    start = end;
                    break;
                }
            }
         }
}
System.out.print(first+"      "+last);
}
}

编辑于 2020-05-30 14:23:44 回复(0)
leetcode 34题
import java.util.*; public class Main{     public static void main(String[] args){         Scanner scan = new Scanner(System.in);         int n = scan.nextInt();         int target = scan.nextInt();         scan.nextLine();         int[] nums = new int[n];         for(int i=0; i<n; i++){             nums[i] = scan.nextInt();         }         System.out.println("["+searchRange(nums,target)[0]+","+searchRange(nums,target)[1]+"]");     }     public static int[] searchRange(int[] nums, int target) {         int[] ans = {-1,-1};         if(nums == null || nums.length == 0) return ans;         int low = 0, high = nums.length-1;         if(low == high && nums[0] == target) return new int[] {0,0};         while(low < high){             int mid = low + (high-low)/2;             if(nums[mid] < target){                 low = mid + 1;             }else{                 high = mid;             }             if(low == high && nums[low] == target){                 ans[0] = low;             }         }         low = 0; high = nums.length-1;         while(low < high){             int mid = low + (high-low+1)/2;             if(nums[mid] > target){                 high = mid - 1;             }else{                 low = mid;             }             if(low == high && nums[low] == target){                 ans[1] = low;             }         }         return ans;     } }
编辑于 2018-03-20 10:45:28 回复(0)
就直接暴力,一个一个的查找是否相等,反正给出的数组是有序的从小到大。
import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();// 表示数组的长度
        int x = scanner.nextInt();// 表示需要查找的数
        int i = 0;// 计数,表示数组的下标,用于存储数
        boolean f=true;
        int[] a = new int[100005];
        while (true) {
            if (n == 0)
                break;
            int y = scanner.nextInt();
            a[i++] = y;
            n--;
        }
        System.out.print("[");
        for (int z = 0; z < i; z++) {
            if (a[z] == x && f) {
                    System.out.print(z+",");
                    f=false;
                }
            if (a[z] > x && f==false){
                System.out.print(--z);//输出最后一个相等的数
                break;
            }
            if(z>=(i-1) && f==false){//考虑特殊情况,数都是一样的
                System.out.print(z);//输出最后一个相等的数
                break;
            }
        }
        if(f)System.out.print("-1,-1");
        System.out.print("]");
        scanner.close();
    }
}


发表于 2017-09-19 10:44:21 回复(1)
用的是折半查找的方法,找到目标数的前一个数不为目标数,则为第一个数;找到目标数的后一个数不为目标数,则为最后一个数
发表于 2017-09-17 09:58:31 回复(0)
 
importjava.util.Scanner;
publicclassMain{
    publicstaticvoidmain(String [] args){
        Scanner in=newScanner(System.in);
        intn=in.nextInt();
        inttarget=in.nextInt();
        intstart=-1,end=-1;
        booleanisStart=true;
        intb[]=newint[n];
        intk=0;
        for(inti=0;i<n;i++){
            b[i]=in.nextInt();
        }
 
        for(inti=0;i<b.length;i++){
            if(b[i]!=target)
                continue;
            elseif(isStart){
                start=i;
                end=i;
                isStart=false;
            }
            else{
                end=i;
            }
        }
        System.out.println("["+start+","+end+"]");
    }
}
发表于 2017-09-15 21:25:34 回复(2)
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int target = sc.nextInt();
        int x = 0;
        int[] numbers = new int[n];
        while (x < n && sc.hasNext()) {
            numbers[x] = sc.nextInt();
            x++;
        }
        int lower = getLower(numbers, target, n);
        int upper = getUpper(numbers, target, n);
        System.out.println("[" + lower + "," + upper + "]");
        sc.close();
    }

    private static int getUpper(int[] numbers, int target, int length) {
        int start = 0;
        int end = length - 1;
        int mid = (start + end) / 2;
        int record = -1;
        while(start <= end){
            if(numbers[mid] <= target){
                if (numbers[mid] == target) record = mid;
                start = mid + 1;
                //if (numbers[mid] < target && start > end) return -1;
            } else {
                end = mid - 1;
            }
            mid = (start + end) / 2;
        }
        if (record == -1) return -1;
        return end;
    }

    private static int getLower(int[] numbers, int target, int length) {
        int start = 0;
        int end = length - 1;
        int mid = (start + end) / 2;
        int record = -1;
        while(start <= end){
            //System.out.println("mid:" + mid);
            //System.out.println("record:" + record);
            if (numbers[mid] == target) record = mid;
            if (numbers[mid] < target){
                start = mid + 1;
                //if (start > end && record == 0) return -1;
            } else {
                end = mid - 1;
            }
            mid = (start + end) / 2;
        }
        if (record == -1) return -1;
        return start;
    }
}
发表于 2017-09-07 13:53:18 回复(0)
折半查找,线性探测
发表于 2017-08-30 19:14:03 回复(0)

问题信息

上传者:小小
难度:
11条回答 2644浏览

热门推荐

通过挑战的用户