1. 程式人生 > 其它 >Day22 在排序陣列中查詢元素的第一個和最後一個位置

Day22 在排序陣列中查詢元素的第一個和最後一個位置

技術標籤:LeetCode刷題集演算法leetcode資料結構

給定一個按照升序排列的整數陣列 nums,和一個目標值 target。找出給定目標值在陣列中的開始位置和結束位置

如果陣列中不存在目標值 target,返回 [-1, -1]。

進階:

你可以設計並實現時間複雜度為 O(log n) 的演算法解決此問題嗎?

https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/

示例1:

輸入:nums = [5,7,7,8,8,10], target = 8
輸出:[3,4]

示例2:

輸入:nums = [5,7,7,8,8,10], target = 6
輸出:[-1,-1]

示例3:

輸入:nums = [], target = 0
輸出:[-1,-1]

提示:

0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums 是一個非遞減陣列
-109 <= target <= 109

Java解法

思路:

  • 跟昨天的型別很相似,就陣列結構有變化,採用相同的二分查詢來進行操作
  • 這裡要注意命中時前後的延伸問題,OK~
package sj.shimmer.algorithm.ten_3;
/** * Created by SJ on 2021/2/15. */ class D22 { public static void main(String[] args) { int[] result1 = searchRange(new int[]{5, 7, 7, 8, 8, 10}, 8); int[] result2 = searchRange(new int[]{5,7,7,8,8,10},6); int[] result3 = searchRange(new int[]{},0); int[] result4 =
searchRange(new int[]{2,2},2); System.out.println(result1[0]+","+result1[1]); System.out.println(result2[0]+","+result2[1]); System.out.println(result3[0]+","+result3[1]); System.out.println(result4[0]+","+result4[1]); } public static int[] searchRange(int[] nums, int target) { int[] result = new int[]{-1,-1}; if (nums != null&&nums.length!=0) { int length = nums.length; int start = 0; int end = length-1; while (start<=end) { int mid = (start+end)/2; if (nums[mid]==target) { //求左邊界 result[0] = mid; result[1] = mid; for (int i = mid-1; i >= 0; i--) { if (nums[i] ==target) { result[0] = i; }else { break; } } //求右邊界 for (int i = mid+1; i < length; i++) { if (nums[i] ==target) { result[1] = i; }else { break; } } return result; } else if (nums[mid] < target) { start = mid+1; }else { end = mid-1; } } } return result; } }

官方解

https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/solution/zai-pai-xu-shu-zu-zhong-cha-zhao-yuan-su-de-di-3-4/

  1. 二分查詢

    主要思想一致,但查詢目標有較小的差異,相比較而言,時間效率差不多,空間上稍微好一點
    核心思路:

    • 要找的就是陣列中「第一個等於target 的位置」(記為 leftIdx)和「第一個大於 target 的位置減一」(記為 rightIdx)
    • 複用方法導致了這裡有些理解麻煩,但核心都是查詢某個具體有限定的位置,相比較我的先命中再查邊界在重複資料較多時更有優勢
    public int[] searchRange(int[] nums, int target) {
        int leftIdx = binarySearch(nums, target, true);
        int rightIdx = binarySearch(nums, target, false) - 1;
        if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] == target && nums[rightIdx] == target) {
            return new int[]{leftIdx, rightIdx};
        } 
        return new int[]{-1, -1};
    }
    
    public int binarySearch(int[] nums, int target, boolean lower) {
        int left = 0, right = nums.length - 1, ans = nums.length;
        while (left <= right) {
            int mid = (left + right) / 2;
            if (nums[mid] > target || (lower && nums[mid] >= target)) {
                right = mid - 1;
                ans = mid;
            } else {
                left = mid + 1;
            }
        }
        return ans;
    }
    

    • 時間複雜度: O(log n)

    • 空間複雜度:O(1)