Leetcode34. Find First and Last Position of Element in Sorted Array

Leetcode34. Find First and Last Position of Element in Sorted Array

Given an array of integers nums sorted in ascending order, find thestarting and ending position of a given target value
Your algorithm’s runtime complexity must be in the order of O(log n).
If the target is not found in the array, return [-1, -1].

Example 1:

Input: nums = [5,7,7,8,8,10], target = 8
Output: [3,4]

Example 2:

Input: nums = [5,7,7,8,8,10], target = 6
Output: [-1,-1]
解法一 线性扫描

target 检查每一个下标,一定能得到正确答案。时间复杂度 O ( N ) O(N) O(N),不符合题意。

解法二 两次二分查找
普通二分查找
int binarySearch(int[] nums, int target) {
    int left = 0; 
    int right = nums.length - 1; 

    while(left <= right) {
        int mid = (right + left) / 2;
        if(nums[mid] == target)
            return mid; 
        else if (nums[mid] < target)
            left = mid + 1; 
        else if (nums[mid] > target)
            right = mid - 1; 
        }
    return -1;
}
  • 注意①:right = nums.length - 1left <= right:搜索区间为[left,right],循环终止条件为left == right + 1,写成区间的形式就是[right + 1, right],而while(left < right)的循环终止条件为left == right
  • 注意②:left = mid + 1right = mid - 1:因为 mid 已经搜索过,应该从搜索区间中去除。
找左侧边界的二分
int left_bound(int[] nums, int target) {
    if (nums.length == 0) return -1;
    int left = 0;
    int right = nums.length; 
    
    while (left < right) { 
        int mid = (left + right) / 2;
        if (nums[mid] == target) {
            right = mid;
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid; 
        }
    }
    // target 比所有数都大
	if (left == nums.length) return -1;
	return nums[left] == target ? left : -1;
}
  • 注意①:right = nums.length;while (left < right):搜索区间为[left,right),循环终止条件为left == right
  • 注意②:left = mid + 1;right = mid:因为是左闭右开,所以当nums[mid] < target时,遍历区间为[mid+1,right),同理当nums[mid] > target时,遍历区间为[left,mid)(因为nums[mid] != target,所以舍弃)。
  • 注意③:返回left的含义:nums[]中小于target的值有left个,即target的下标正好为nums[left]
  • 注意④:nums[mid] == target后令right = mid:首先因为循环终止条件为left == right,故即使此mid为唯一一个target,程序也可以返回正确的结果;找到 target 时,在区间 [left, mid) 中继续搜索,不断向左收缩,达到锁定左侧边界的目的。
  • 注意⑤:返回leftright是一样的因为循环终止条件为left == right
找右侧边界的二分
int right_bound(int[] nums, int target) {
    if (nums.length == 0) return -1;
    int left = 0, right = nums.length;
    
    while (left < right) {
        int mid = (left + right) / 2;
        if (nums[mid] == target) {
            left = mid + 1; 
        } else if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid;
        }
    }
    if (left == 0) return -1;
	return nums[left-1] == target ? (left-1) : -1;
}
  • 注意①:nums[mid] == target后令left = mid + 1,找到 target 时,在区间 [mid+1, right) 中继续搜索,不断向右收缩,达到锁定右侧边界的目的。循环的结束条件是left == right
  • 注意②:返回left - 1
Java
public class Solution {
    public int[] searchRange(int[] nums, int target) {
        int len = nums.length;
        if (len == 0) {
            return new int[]{-1, -1};
        }
        int firstPosition = findFirstPosition(nums, target);
        if (firstPosition == -1) {
            return new int[]{-1, -1};
        }
        int lastPosition = findLastPosition(nums, target);
        return new int[]{firstPosition, lastPosition};
    }

    private int findFirstPosition(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            int mid = (left + right) >>> 1;
            // 小于一定不是解
            if (nums[mid] < target) {
                // 下一轮搜索区间是 [mid + 1, right]
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        if (nums[left] == target) {
            return left;
        }
        return -1;
    }

    private int findLastPosition(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        while (left < right) {
            int mid = (left + right + 1) >>> 1;
            // 大于一定不是解
            if (nums[mid] > target) {
                // 下一轮搜索区间是 [left, mid - 1]
                right = mid - 1;
            } else {
                left = mid;
            }
        }
        return left;
    }
}
C++
#include <iostream>
#include <vector>

using namespace std;


class Solution {
private:
    int findFitstPosition(vector<int> &nums, int target) {
        int size = nums.size();
        int left = 0;
        int right = size - 1;
        while (left < right) {
            int mid = (left + right) >> 1;
            if (nums[mid] < target) {
                left = mid + 1;
            } else {
                right = mid;
            }
        }
        if (nums[left] != target) {
            return -1;
        }
        return left;
    }

    int findLastPosition(vector<int> &nums, int target) {
        int size = nums.size();
        int left = 0;
        int right = size - 1;
        while (left < right) {
            int mid = (left + right + 1) >> 1;
            if (nums[mid] > target) {
                right = mid - 1;
            } else {
                left = mid;

            }
        }
        if (nums[left] != target) {
            return -1;
        }
        return left;
    }

public:
    vector<int> searchRange(vector<int> &nums, int target) {
        int size = nums.size();
        if (size == 0) {
            return {-1, -1};
        }
        int fitstPosition = findFitstPosition(nums, target);

        if (fitstPosition == -1) {
            return {-1, -1};
        }
        int lastPosition = findLastPosition(nums, target);
        return {fitstPosition, lastPosition};
    }
};
Python
from typing import List


class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        size = len(nums)
        if size == 0:
            return [-1, -1]

        first_position = self.__find_first_position(nums, size, target)
        if first_position == -1:
            return [-1, -1]
        last_position = self.__find_last_position(nums, size, target)
        return [first_position, last_position]

    def __find_first_position(self, nums, size, target):
        left = 0
        right = size - 1
        while left < right:
            mid = (left + right) >> 1
            if nums[mid] < target:
                left = mid + 1
            else:
                right = mid

        if nums[left] == target:
            return left
        else:
            return -1

    def __find_last_position(self, nums, size, target):
        left = 0
        right = size - 1
        while left < right:
            mid = (left + right + 1) >> 1
            if nums[mid] > target:
                right = mid - 1
            else:
                left = mid

        # 由于能走到这里,说明在数组中一定找得到目标元素
        # 因此这里不用再做一次判断
        return left
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值