面试之基础算法题:求一个数字在给定的已排序数组中出现的起始、终止索引号(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;
    }   
}

变形

上面的问法可以经过变形,换一种表现形式来提问:

  1. 假设给定一个有序的整型数组arr,以及整数 k,问k在数组中出现几次?
    根据上面求得的first_index和last_index,即可得到出现次数为: (last_index - first_index) + 1

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

johnny233

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值