题目
给定一个升序的整数数组,查找某一个值在数组中出现的索引号,例如,输入数组[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
。
参考