Python編程題52--在排序列表中查找元素的第一個和最後一個位置

題目

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

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

例如:

給定一個列表 nums :[5, 7, 7, 8, 8, 10],target = 8
返回結果:[3, 4]

給定一個列表 nums :[5, 7, 7, 8, 8, 10],target = 6
返回結果:[-1, -1]

給定一個列表 nums :[],target = 0
返回結果:[-1, -1]

實現思路1

  • 定義2個變量:left_index、right_index ,分別表示開始位置和結束位置,默認值均爲 -1
  • 直接進行一輪遍歷,如果列表中存在目標值 target,那麼就記錄第一個出現的位置,並更新到 left_index、right_index,如果在剩餘列表元素中依然存在目標值 target,那麼就只更新 right_index

代碼實現

class Solution:
    def search_range(self, nums, target):
        left_index, right_index = -1, -1
        for i, value in enumerate(nums):
            if value == target and left_index == -1:
                left_index = i
            if value == target:
                right_index = i
        return [left_index, right_index]
  • 時間複雜度:O(n)
  • 空間複雜度:O(1)

實現思路2

  • 使用 二分查找 來實現
  • 定義2個變量:left_index、right_index ,分別表示開始位置和結束位置,通過二分查找判斷,如果列表 nums 中不存在目標值 target,則直接返回 [-1, -1],如果列表中存在目標值 target,並且查找出來的目標值下標爲 index ,那麼就將 left_index、right_index 均更新爲 index
  • 在上面二分查找時,因爲列表中可能存在多個相同元素,所以查找出來的 index 不一定是目標值 target 在列表中第一個出現的位置,因此需要對 left_index、right_index 做進一步處理
  • 對於left_index,如果其左側的元素也等於目標值,即nums[left_index - 1] == target,那麼就連續更新 left_index = left_index - 1,直到 left_index 恰爲目標值在列表中第一個出現的下標位置
  • 對於right_index,如果其右側的元素也等於目標值,即nums[right_index + 1] == target,那麼就連續更新 right_index = right_index + 1,直到 right_index 恰爲目標值在列表中最後一個出現的下標位置

代碼實現

class Solution:
    def search_range(self, nums, target):
        index = self.binary_search(nums, target)
        if index == -1:  # 如果列表中不存在 target
            return [-1, -1]
        left_index, right_index = index, index
        while left_index > 0 and nums[left_index - 1] == target:  # 處理 left_index,找到第一個出現位置
            left_index -= 1
        while right_index < len(nums) - 1 and nums[right_index + 1] == target:  # 處理 right_index,找到最後一個出現位置
            right_index += 1
        return [left_index, right_index]

    def binary_search(self, nums, target):  # 二分查找
        left, right = 0, len(nums) - 1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] > target:
                right = mid - 1
            elif nums[mid] < target:
                left = mid + 1
            else:
                return mid
        return -1

從上面可以看到,如果列表中可能存在多個相同元素,那麼我們通過二分查找法查找返回的元素下標可能不是第一個出現位置,因此,我們可以對上面的二分查找進行改進:

  • 在二分查找函數 binary_search() 的參數中增加一個參數:flag
  • 如果flag爲True,那麼表示查找列表nums中第一個大於等於target的下標
  • 如果flag爲False,那麼表示查找列表nums中第一個大於target的下標

優化後的代碼如下:

class Solution:
    def search_range(self, nums, target):
        left_index = self.binary_search(nums, target, True)  # 查找第一個大於等於target的索引
        right_index = self.binary_search(nums, target, False)  # 查找第一個大於target的索引
        if left_index <= right_index - 1 and nums[left_index] == target and nums[right_index - 1] == target:
            return [left_index, right_index - 1]
        return [-1, -1]

    def binary_search(self, nums, target, flag):  # 改進後的二分查找
        left, right, index = 0, len(nums) - 1, len(nums)
        while left <= right:
            mid = (left + right) // 2
            if (nums[mid] > target) or (flag and nums[mid] >= target):
                right = mid - 1
                index = mid
            else:
                left = mid + 1
        return index
  • 時間複雜度:O(log n)
  • 空間複雜度:O(1)

更多Python編程題,等你來挑戰:Python編程題彙總(持續更新中……)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章