面试之基础算法题:求一个数字在给定的已排序数组中出现的起始、终止索引号(Java版)
题目
给定一个升序的整数数组,查找某一个值在数组中出现的索引号,例如,输入数组[2, 3, 3, 4, 4, 5]
;查找的数是3,则返回[1, 2]
。时间复杂度要求为O(logN)。
思路
基本上大致思考一番,就知道可以用二分查找法求解。
然后因为java不能在一个方法里面返回两个int常量,当然返回一个List<Integer>
另当别论,此处的思路就是两个查找方法,分别查找起始索引和终止索引。
起始索引:
起始索引的定位,首先比较中间的数和要查找的数 target,如果 target 小于中间的数,那么在数组的左半部分继续查找,如果 target 大于中间的数,在数组的右半部分继续查找;如果 target 和中间的数相等,那么比较中间数字的前一个数字是否和 target 相等,如果不相等,那么当前的中间索引就是起始索引,如果相等,那么继续在前半部分查找;
类似地,定位终止索引时,如果 target 和中间的数相等时,那么比较中间数字的后一个数字是否和 target 相等,如果不相等,那么当前的中间索引就是终止索引,如果相等,那么继续在后半部分查找。
实现
package algorithm.interview;
/**
* Author: Johnny
* Date: 2018/5/15
* Time: 22:02
* 给定一个升序的整数数组,查找某一个值在数组中出现的索引号,例如,输入数组2,3,3,4,4,5;查找的数是3,则返回1,2。时间复杂度要求为O(logN)
*/
public class GetFirstLastIndex {
public static void main(String[] args) {
int[] sortedArray = {1, 1, 2, 3, 3, 6, 6, 6, 6, 9, 9, 10};
int length = sortedArray.length;
int target = 6;
System.out.println(getFirstTarget(sortedArray, length, target, 0, length - 1));
System.out.println(getSecondTarget(sortedArray, length, target, 0, length - 1));
}
/**
* 寻找开始索引
*/
static int getFirstTarget(int[] array, int n, int target, int nStart, int nEnd) {
if (nStart > nEnd) {
// 返回-1表示没有待查询的元素
return -1;
}
// 中间索引
int nMid = nStart + ((nEnd - nStart) >> 1);
int nMidData = array[nMid];
while (nStart <= nEnd) {
if (target > nMidData) {
nStart = nMid + 1;
} else if (target < nMidData) {
nEnd = nMid - 1;
} else {
if ((target != array[nMid - 1] && nMid > 0) || nMid == 0) {
return nMid;
} else {
nEnd = nMid - 1;
}
}
// 更新中间值得索引和值
nMid = nStart + ((nEnd - nStart) >> 1);
// 数组越界判断
if (nMid < 0) {
return -1;
}
nMidData = array[nMid];
}
return -1;
}
/**
* 寻找结束索引
*/
static int getSecondTarget(int[] array, int n, int target, int nStart, int nEnd) {
if (nStart > nEnd) {
return -1;
}
// 中间索引
int nMid = nStart + ((nEnd - nStart) >> 1);
int nMidData = array[nMid];
while (nStart <= nEnd) {
if (target > nMidData) {
nStart = nMid + 1;
} else if (target < nMidData) {
nEnd = nMid - 1;
} else {
if ((target != array[nMid + 1] && nMid < n) || nMid == n - 1) {
return nMid;
} else {
nStart = nMid + 1;
}
}
//更新中间值得索引和值
nMid = nStart + ((nEnd - nStart) >> 1);
if (nMid < 0) {
return -1;
}
nMidData = array[nMid];
}
return -1;
}
}
变形
上面的问法可以经过变形,换一种表现形式来提问:
- 假设给定一个有序的整型数组arr,以及整数 k,问k在数组中出现几次?
根据上面求得的first_index和last_index,即可得到出现次数为:(last_index - first_index) + 1
。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix