数字在排序数组中出现的起始索引号

题目如下:

给定一个升序的整数数组,查找某一个值在数组中出现的索引号,例如,输入数组2,3,3,4,4,5;查找的数是3,则返回1,2。时间复杂度要求为O(logN)。

初次拿到这个题目可以立即想到用二分查找来做,先比较中间的数和要查找的数,如果关键字(要查找的数)小于中间的数,那么在数组的左半部分继续查找,如果关键字大于中间的数,那么在数组的右半部分继续查找,如果关键字和中间的数相等,那么先比较中间数字的前一个数字是否和关键字相等,如果相等,继续用关键字和前一个数字的前一个数字比较,如果不等,那么当前数字就是要查找的数字,其所在的索引就是第一次出现的地方。对于结束的索引,可以用类似的方法来做,先比较中间数字的后一个数字是否和关键字相等,如果相等,继续用关键字和后一个数字的后一个数字比较,如果不等,那么当前数字就是要查找的数字,其所在的索引就是最后一次出现的地方。但是这样做,最坏的情况下,时间复杂度会退化为O(N),即当数组是同一个数的时候。所以这种方法不是时间上最优的。

其实,本题目是二分查找的变种,我们可以分为两步来做,第一步,求得该数字第一次出现的索引,第二步,求得该数字最后一次出现的索引。

首先来看第一次出现的索引怎么来求,首先比较中间的数和要查找的数,如果关键字(要查找的数)小于中间的数,那么在数组的左半部分继续查找,如果关键字大于中间的数,那么在数组的右半部分继续查找,如果关键字和中间的数相等,那么比较中间数字的前一个数字是否和关键字相等,如果不相等,那么当前的中间索引就是第一次出现的索引,如果相等,那么继续在前半部分查找。具体的实现代码如下:

//寻找开始索引
int GetFirstTarget(int A[], int n, int target,int nStart,int nEnd)
{
	if (nStart > nEnd)
	{
		return -1;
	}

	//中间索引
	int nMid = nStart + ( (nEnd-nStart) >> 1);
	int nMidData = A[nMid];

	while (nStart <= nEnd)
	{
		if (target > nMidData)
		{
			nStart = nMid+1;
		}

		else if (target < nMidData)
		{
			nEnd = nMid-1;
		}

		else if (target == nMidData)
		{
			if ((target != A[nMid-1] && nMid > 0) || nMid == 0)
			{
				return nMid;
			}

			else
				nEnd = nMid-1;
		}

		//更新中间值得索引和值
		nMid = nStart + ( (nEnd-nStart) >> 1);
		nMidData = A[nMid];
	}

	return -1;
}

寻找最后一次出现的索引也可以用类似的思路来做:首先比较中间的数和要查找的数,如果关键字(要查找的数)小于中间的数,那么在数组的左半部分继续查找,如果关键字大于中间的数,那么在数组的右半部分继续查找,如果关键字和中间的数相等,那么比较中间数字的后一个数字是否和关键字相等,如果不相等,那么当前的中间索引就是最后一次出现的索引,如果相等,那么继续在后半部分查找。寻找第一个索引和最后一个索引的具体差别可以注意红色字体的字眼,具体的实现代码如下:

//寻找结束索引
int GetSecondTarget(int A[], int n, int target,int nStart,int nEnd)
{
	if (nStart > nEnd)
	{
		return -1;
	}

	//中间索引
	int nMid = nStart + ( (nEnd-nStart) >> 1);
	int nMidData = A[nMid];

	while (nStart <= nEnd)
	{
		if (target > nMidData)
		{
			nStart = nMid+1;
		}

		else if (target < nMidData)
		{
			nEnd = nMid-1;
		}

		else if (target == nMidData)
		{
			if ((target != A[nMid+1] && nMid < n) || nMid == n-1)
			{
				return nMid;
			}

			else
				nStart = nMid+1;
		}

		//更新中间值得索引和值
		nMid = nStart + ( (nEnd-nStart) >> 1);
		nMidData = A[nMid];
	}

	return -1;
}

最后就是主功能函数进行调用了,其代码如下:

vector<int> searchRange(int A[], int n, int target)
{
	std::vector<int> vecIndex;
	vecIndex.resize(2);
	vecIndex[0] = -1;
	vecIndex[1] = -1;

	if (A == NULL || n <= 0)
	{
		return vecIndex;
	}

	vecIndex[0] = GetFirstTarget(A,n,target,0,n-1);
	vecIndex[1] = GetSecondTarget(A,n,target,0,n-1);

	return vecIndex;
}

两次查找的时间复杂度都是O(logN),所以总的时间复杂度就是O(logN)。

最后,这个题目还有另外一个变种就是数字在排序数组中出现的次数

时间: 2024-08-28 05:39:13

数字在排序数组中出现的起始索引号的相关文章

数字在排序数组中出现的起始索引號

题目例如以下: 给定一个升序的整数数组.查找某一个值在数组中出现的索引號.比如.输入数组2,3.3,4,4.5:查找的数是3,则返回1,2. 时间复杂度要求为O(logN). 初次拿到这个题目能够马上想到用二分查找来做.先比較中间的数和要查找的数.假设keyword(要查找的数)小于中间的数,那么在数组的左半部分继续查找.假设keyword大于中间的数.那么在数组的右半部分继续查找,假设keyword和中间的数相等.那么先比較中间数字的前一个数字是否和keyword相等,假设相等.继续用keyw

数字在排序数组中出现的次数

题目:统计一个数字在排序数组中出现的次数.例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4. 程序实现: import java.util.Scanner; public class Test38 { public static void main(String[] args) { /**  * 初始化数组,测试数据可以多种途径初始化  */   Scanner in = new Scanner(System.in); /*int[] a = 

九度oj 题目1349:数字在排序数组中出现的次数

题目描述: 统计一个数字在排序数组中出现的次数. 输入: 每个测试案例包括两行: 第一行有1个整数n,表示数组的大小.1<=n <= 10^6. 第二行有n个整数,表示数组元素,每个元素均为int. 第三行有1个整数m,表示接下来有m次查询.1<=m<=10^3. 下面有m行,每行有一个整数k,表示要查询的数. 输出: 对应每个测试案例,有m行输出,每行1整数,表示数组中该数字出现的次数. 样例输入: 8 1 2 3 3 3 3 4 5 1 3 样例输出: 4 使用库函数即可解决

数字在排序数组中出现的次数(剑指offer)利用快排思想(O(logn))

数字在排序数组中出现的次数 参与人数:1216时间限制:1秒空间限制:32768K 通过比例:28.43% 最佳记录:0 ms|0K(来自 ) 题目描述 统计一个数字在排序数组中出现的次数. 题意:首先数组是个已经排列的有序递增序列!统计一个数出现的次数,相当于在有序的序列里插入一个数,那么我只要确定插入的位置,利用快排的思想,也可以说是二分,如果在数组中找到k,那么左右拓展边界就可以确定,该数在数组中出现的次数了. 一些特殊情况可以特判!比如k小于数组最小数,或者大于数组最大数: class

剑指offer 面试题38—数字在排序数组中出现的次数

题目: 统计一个数字在排序数组中出现的次数.例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4. 解法一:O(n) 顺序遍历 解法二:O(logn) 用二分查找,分别找出第一个3,和最后一个3的位置,然后计算个数. #include <stdio.h> int GetFirstK(int* data,int length,int k,int start,int end) { if(start > end) return -1; int m

剑指offer面试题38:数字在排序数组中出现的次数

题目描述: 统计一个数字在排序数组中出现的次数. 输入: 每个测试案例包括两行: 第一行有1个整数n,表示数组的大小.1<=n <= 10^6. 第二行有n个整数,表示数组元素,每个元素均为int. 第三行有1个整数m,表示接下来有m次查询.1<=m<=10^3. 下面有m行,每行有一个整数k,表示要查询的数. 输出: 对应每个测试案例,有m行输出,每行1整数,表示数组中该数字出现的次数. 样例输入: 81 2 3 3 3 3 4 513 样例输出: 4 //source:http

编程算法 - 数字在排序数组中出现的次数 代码(C)

数字在排序数组中出现的次数 代码(C) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 统计一个数字在排序数组中出现的次数. 通过折半查找, 找到首次出现的位置, 再找到末次出现的位置, 相减即可. 时间复杂度O(logn). 代码: /* * main.cpp * * Created on: 2014.6.12 * Author: Spike */ /*eclipse cdt, gcc 4.8.1*/ #include <stdio.h> #inc

【剑指offer】面试题38:数字在排序数组中出现的次数

题目: 统计一个数字在排序数组中出现的次数. 思路: 对二分查找进行改进,找到数字在数组中第一次出现和最后一次出现的位置,这样就得到它出现的次数. 以找第一次出现的位置为例:如果mid元素大于k,则在前半段找:如果小于k,则在后半段找:如果等于k,则要看mid的前一个元素是不是k,如果是,则在前半段找,如果不是,则这就是第一次出现的位置. 时间复杂度O(logn). 代码: class Solution { public: int GetNumberOfK(vector<int> data ,

【剑指offer】数字在排序数组中出现的次数

转载请注明出处:http://blog.csdn.net/ns_code/article/details/27364557 题目描写叙述: 统计一个数字在排序数组中出现的次数. 输入: 每一个測试案例包括两行: 第一行有1个整数n,表示数组的大小.1<=n <= 10^6. 第二行有n个整数,表示数组元素,每一个元素均为int. 第三行有1个整数m,表示接下来有m次查询.1<=m<=10^3. 以下有m行,每行有一个整数k,表示要查询的数. 输出: 相应每一个測试案例,有m行输出,