LeetCode - 34 Find the first and last position of an element in a sorted array

Table of contents

Topic source

topic description

example

hint

topic analysis

Algorithm source code


Topic source

34. Find the first and last position of an element in a sorted array - LeetCode

topic description

You are given an integer array nums in non-decreasing order, and a target value target. Please find out where the given target value starts and ends in the array.

If the target value target does not exist in the array, return [-1, -1].

You have to design and implement an algorithm with time complexity O(log n) to solve this problem.

example

enter nums = [5,7,7,8,8,10], target = 8
output [3,4]
illustrate none
enter nums = [5,7,7,8,8,10], target = 6
output [-1,-1]
illustrate none
enter nums = [], target = 0
output [-1,-1]
illustrate none

 

hint

  • 0 <= nums.length <= 105
  • -109 <= nums[i] <= 109
  • nums is a non-decreasing array
  • -109 <= target <= 109

topic analysis

The nums in this question is an integer array nums arranged in non-decreasing order, which means that there are repeated values ​​in nums, so the elements to be searched in this question have the concept of the first and last positions.

This question requires us to complete the search of the first and last position of the element within the time complexity of O(logN), which is easy to think of binary search, because the nums of this question is monotonous, and the time complexity of binary is also O (logN)

However, commonly used binary search, such as Arrays.binarySearch in the Java language, is not suitable for finding the position of elements with duplicate values. For example, the position of the element 1 to be found in the following code is finally returned as index 2.

import java.util.Arrays;

public class Main {
  public static void main(String[] args) {
    int[] arr = {1, 1, 1, 1, 1};
    System.out.println(Arrays.binarySearch(arr, 1));
  }
}

This is related to the underlying binary search strategy. For binary search, you can read the implementation of binary search in this blog:

Algorithm Design - Dichotomy and Trichotomy, Luogu P3382 - blog outside Fucheng - CSDN Blog

The standard binary search implementations for the three languages ​​are given below

Java standard binary search implementation

import java.util.*;
 
public class Main {
  public static void main(String[] args) {
	  int[] arr = {1,1,1,1,1};
	  System.out.println(binarySearch(arr, 1));
  }
  
  public static int binarySearch(int[] arr, int target) {
    int low = 0;
    int high = arr.length - 1;

    while (low <= high) {
      int mid = (low + high) >> 1;
      int midVal = arr[mid];

      if (midVal > target) {
        high = mid - 1;
      } else if (midVal < target) {
        low = mid + 1;
      } else {
        return mid; // midVal == target,则直接返回mid作为target的位置
      }
    }

    return -low - 1; // 找不到则返回插入位置
  }
}

JavaScript standard binary search implementation

function binarySearch(arr, target) {
  let low = 0;
  let high = arr.length - 1;

  while (low <= high) {
    const mid = (low + high) >> 1;
    const midVal = arr[mid];

    if (midVal > target) {
      high = mid - 1;
    } else if (midVal < target) {
      low = mid + 1;
    } else {
      return mid; // midVal == target,则直接返回mid作为target的位置
    }
  }

  return -low - 1; // 找不到则返回插入位置
}

Python binary search standard implementation

def binarySearch(arr, target):
    low = 0
    high = len(arr) - 1

    while low <= high:
        mid = (low + high) >> 1
        midVal = arr[mid]

        if midVal > target:
            high = mid - 1
        elif midVal < target:
            low = mid + 1
        else:
            return mid

    return -low - 1

In the standard binary search framework, if midVal == target, the mid value at this time is directly returned as the position of the target.

But if the target has multiple elements with repeated values, then when midVal == target, you should not arbitrarily determine that mid is the position of target, but try to extend the judgment to the left and right of the mid position:

Extend judgment to the left of the mid position:

  • If mid == 0 or arr[mid] != arr[mid-1], it means that the current mid position is already the left boundary of the target number field, that is, the position where the target appears for the first time
  • If mid > 0 and arr[mid] == arr[mid - 1], it means that the left boundary of the target number field is still to the left of the mid position. At this time, in order to find the left boundary, we should set high = mid - 1

Extend judgment to the right of the mid position:

  • If mid == arr.length - 1 or arr[mid] != arr[mid + 1], it means that the current mid position is already the right boundary of the target number field, that is, the position where the target appeared last
  • If mid < nums.length -1 and arr[mid] == arr[mid+1], it means that the right boundary of the target number field is still on the right side of the mid position. At this time, in order to find the right boundary, we should let low = mid + 1

The implementation code is as follows:

Java implementation code

import java.util.*;
 
public class Main {
  public static void main(String[] args) {
	  int[] arr = {1,1,1,1,1};
	  System.out.println(binarySearch(arr, 1));
  }
  
  public static int searchFirst(int[] arr, int target) {
    int low = 0;
    int high = arr.length - 1;

    while (low <= high) {
      int mid = (low + high) >> 1;
      int midVal = arr[mid];

      if (midVal > target) {
        high = mid - 1;
      } else if (midVal < target) {
        low = mid + 1;
      } else {
		// 向左延伸判断,mid是否为target数域的左边界,即第一次出现的位置
		if(mid == 0 || arr[mid] != arr[mid - 1]) {
			return mid;
		} else {
			high = mid - 1;
		}
      }
    }

    return -low - 1; // 找不到则返回插入位置
  }
  
  public static int searchLast(int[] arr, int target) {
    int low = 0;
    int high = arr.length - 1;

    while (low <= high) {
      int mid = (low + high) >> 1;
      int midVal = arr[mid];

      if (midVal > target) {
        high = mid - 1;
      } else if (midVal < target) {
        low = mid + 1;
      } else {
		// 向右延伸判断,mid是否为target数域的右边界,即最后一次出现的位置
		if(mid == nums.length - 1 || arr[mid] != arr[mid + 1]) {
			return mid;
		} else {
			low = mid + 1;
		}
      }
    }

    return -low - 1; // 找不到则返回插入位置
  }
}

JavaScript implementation code

function searchFirst(arr, target) {
  let low = 0;
  let high = arr.length - 1;

  while (low <= high) {
    const mid = (low + high) >> 1;
    const midVal = arr[mid];

    if (midVal > target) {
      high = mid - 1;
    } else if (midVal < target) {
      low = mid + 1;
    } else {
      // 向左延伸判断,mid是否为target数域的左边界,即第一次出现的位置
      if (mid == 0 || arr[mid] != arr[mid - 1]) {
        return mid;
      } else {
        high = mid - 1;
      }
    }
  }

  return -low - 1; // 找不到则返回插入位置
}

function searchLast(arr, target) {
  let low = 0;
  let high = arr.length - 1;

  while (low <= high) {
    const mid = (low + high) >> 1;
    const midVal = arr[mid];

    if (midVal > target) {
      high = mid - 1;
    } else if (midVal < target) {
      low = mid + 1;
    } else {
      // 向右延伸判断,mid是否为target数域的右边界,即最后一次出现的位置
      if (mid == arr.length - 1 || arr[mid] != arr[mid + 1]) {
        return mid;
      } else {
        low = mid + 1;
      }
    }
  }

  return -low - 1; // 找不到则返回插入位置
}

Python implementation code

def searchFirst(arr, target):
    low = 0
    high = len(arr) - 1

    while low <= high:
        mid = (low + high) >> 1
        midVal = arr[mid]

        if midVal > target:
            high = mid - 1
        elif midVal < target:
            low = mid + 1
        else:
            if mid == 0 or arr[mid] != arr[mid - 1]:
                return mid
            else:
                high = mid - 1

    return -low - 1


def searchLast(arr, target):
    low = 0
    high = len(arr) - 1

    while low <= high:
        mid = (low + high) >> 1
        midVal = arr[mid]

        if midVal > target:
            high = mid - 1
        elif midVal < target:
            low = mid + 1
        else:
            if mid == len(arr) - 1 or arr[mid] != arr[mid + 1]:
                return mid
            else:
                low = mid + 1

    return -low - 1

Java algorithm source code

class Solution {
    public int[] searchRange(int[] nums, int target) {
        return new int[]{search(nums, target, true), search(nums, target, false)};
    }

    public int search(int[] nums, int target, boolean isFirst) {
        int low = 0;
        int high = nums.length - 1;

        while(low <= high) {
            int mid = (low + high) >> 1;
            int midVal = nums[mid];

            if(midVal > target) {
                high = mid - 1;
            } else if(midVal < target) {
                low = mid + 1;
            } else {
                if(isFirst) {
                    // 查找元素的第一个位置
                    if(mid == 0 || nums[mid] != nums[mid-1]){
                        return mid;
                    } else {
                        high = mid - 1;
                    }
                } else {
                    // 查找元素的最后一个位置
                    if(mid == nums.length - 1 || nums[mid] != nums[mid + 1]) {
                        return mid;
                    } else {
                        low = mid + 1;
                    }
                }
                
            }
        }

        return -1;
    }
}

 

JavaScript algorithm source code

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var searchRange = function(nums, target) {
    function search(nums, target, isFirst) {
        let low = 0;
        let high = nums.length - 1;

        while(low <= high) {
            const mid = (low + high) >> 1;
            const midVal = nums[mid];

            if(midVal > target) {
                high = mid - 1;
            } else if(midVal < target) {
                low = mid + 1;
            } else {
                if(isFirst) {
                    if(mid == 0 || nums[mid] != nums[mid-1]) {
                        return mid;
                    } else {
                        high = mid - 1;
                    }
                } else {
                    if(mid == nums.length - 1 || nums[mid] != nums[mid + 1]) {
                        return mid;
                    } else {
                        low = mid + 1;
                    }
                }
            }
        }

        return -1;
    }

    return [search(nums, target, true), search(nums, target, false)];
};

 

Python algorithm source code

class Solution(object):
    def searchRange(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        return self.search(nums, target, True), self.search(nums, target, False)
    
    def search(self, nums, target, isFirst):
        low = 0
        high = len(nums) - 1

        while low <= high:
            mid = (low + high) >> 1
            midVal = nums[mid]

            if midVal > target:
                high = mid - 1
            elif midVal < target:
                low = mid + 1
            else:
                if isFirst:
                    if mid == 0 or nums[mid] != nums[mid-1]:
                        return mid
                    else:
                        high = mid - 1
                else:
                    if mid == len(nums) - 1 or nums[mid] != nums[mid + 1]:
                        return mid
                    else:
                        low = mid + 1
        
        return -1

Guess you like

Origin blog.csdn.net/qfc_128220/article/details/130669841