leecode34在排序数组中查找元素的第一个和最后一个位置-手写详解

文章介绍了一种在排序数组中查找目标值第一个和最后一个位置的方法,通过二分搜索确定左右边界。当range范围小时,方法具有较低的时间复杂度,但范围大时比双二分搜索算法效率低。文中提供了两种实现,包括优化过的滑动下标方法和双二分法,后者能更精确地找到边界。
摘要由CSDN通过智能技术生成

源代码的一些注解

我这个的思路是先找出这个target,找到了之后在便利这个target周围的变量,相当于是做了一个二分搜索算法之后,当这个range范围比较小的时候我这种方法的时间复杂度比较低,但是当这个range范围比较大的时候我的时间复杂度应该是比两个二分搜索算法所需时间多的.
我在代码随想录网站上看的这个题的题解是利用了两个二分搜索法进行计算,第一个二分搜索确定左边界,第二个二分搜索算法确定右边界,然后最后确定这个总边界.相对而言时间复杂度会更高一点.我自己做题的时候并没有想到这个算法.

源代码

package 数组;
import java.util.Scanner;
public class 在排序数组中查找元素的第一个和最后一个位置 {
    public static void main(String[] args) {
        int n;
        Scanner input = new Scanner(System.in);
        System.out.println("请输入数组的长度");
        n=input.nextInt();
        int[] num = new int[n];
        System.out.println("按照递增的顺序输入数组的元素");
        for (int i = 0; i < num.length; i++) {
            num[i]= input.nextInt();
        }
        System.out.println("请输入你要查找的目标值");
        int target = input.nextInt();
        int[] result= searchRange(num,target);
        for (int i = 0; i < result.length; i++) {
            System.out.println(result[i]);
        }
    }
    public static int[] searchRange(int []nums,int target) {
        int length = nums.length;
        int left = 0, right = length - 1;
        int m = 0;
        int min = 0, max = 0;
        while (left <= right) {
            m = (left + right) / 2;
            if (nums[m] < target) {
                left = m + 1;
            } else if (nums[m] > target) {
                right = m - 1;
            } else {
                max = m;
                min = m;
                while (true) {
                    //数组越界问题
                    if ((max+1)!=length&&nums[max + 1] == target) {
                        max++;
                    }
                    if ((min-1)!=-1&&nums[min - 1] == target) {
                        min--;
                    }
                    if (((min-1)==-1||nums[min - 1] != target) && ((max+1)==length||nums[max + 1] != target)) {
                        break;
                    }
                }
                int[] result = new int[]{min, max};
                return result;
            };
        }
        //第一次错误,漏掉了这个特殊情况
        max=-1;
        min=-1;
        int[] result = new int[]{min, max};
        return result;
    }
}

关于滑动这个数组下标我这个还可以在进行优化,相比我的所用时间会更小

	// 向左滑动,找左边界
	while (left - 1 >= 0 && nums[left - 1] == nums[index]) { // 防止数组越界。逻辑短路,两个条件顺序不能换
		left--;
	}
	// 向左滑动,找右边界
	while (right + 1 < nums.length && nums[right + 1] == nums[index]) { // 防止数组越界。
		right++;
	}
	return new int[] {left, right};

双二分法确定上下边界

class Solution {
    int[] searchRange(int[] nums, int target) {
        int leftBorder = getLeftBorder(nums, target);
        int rightBorder = getRightBorder(nums, target);
        // 情况一
        if (leftBorder == -2 || rightBorder == -2) return new int[]{-1, -1};
        // 情况三
        if (rightBorder - leftBorder > 1) return new int[]{leftBorder + 1, rightBorder - 1};
        // 情况二
        return new int[]{-1, -1};
    }

    int getRightBorder(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况
        while (left <= right) {
            int middle = left + ((right - left) / 2);
            if (nums[middle] > target) {
                right = middle - 1;
            } else { // 寻找右边界,nums[middle] == target的时候更新left
                left = middle + 1;
                rightBorder = left;
            }
        }
        return rightBorder;
    }

    int getLeftBorder(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int leftBorder = -2; // 记录一下leftBorder没有被赋值的情况
        while (left <= right) {
            int middle = left + ((right - left) / 2);
            if (nums[middle] >= target) { // 寻找左边界,nums[middle] == target的时候更新right
                right = middle - 1;
                leftBorder = right;
            } else {
                left = middle + 1;
            }
        }
        return leftBorder;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值