返回

巧用二分法算法,征服LeetCode 34与33!

前端

二分法算法的精髓
二分法算法是一种高效的搜索算法,它通过不断缩小候选区间的范围来快速找到目标元素。其关键思想是基于这样的假设:在候选区间中,存在我们要找到的答案,而且这个区间拥有单调性(即元素值按照一定的顺序排列)。通过不停地缩减候选区间的范围,我们可以排除无用答案,最终找到目标元素。

二分法算法的步骤如下:

  1. 将候选区间定义为整个数组。
  2. 计算候选区间的中间位置。
  3. 将目标元素与候选区间的中间元素进行比较。
  4. 如果目标元素等于候选区间的中间元素,则目标元素已找到,算法停止。
  5. 如果目标元素小于候选区间的中间元素,则将候选区间更新为候选区间的左半部分。
  6. 如果目标元素大于候选区间的中间元素,则将候选区间更新为候选区间的右半部分。
  7. 重复步骤2-6,直到目标元素被找到或候选区间为空。

LeetCode 34. 在排序数组中查找元素的第一个和最后一个位置

问题
给定一个已排序的数组和一个目标元素,返回该目标元素在数组中出现的第一个和最后一个位置。如果目标元素在数组中不存在,则返回[-1, -1]。

思路分析
我们可以使用二分法算法来解决这个问题。首先,我们可以使用二分法算法找到目标元素在数组中出现的位置。然后,我们可以使用两个指针分别指向目标元素的第一个和最后一个位置,并通过二分法算法来找到这两个指针指向的位置。

代码实现

def search_range(nums, target):
    """
    :type nums: List[int]
    :type target: int
    :rtype: List[int]
    """
    # 使用二分法查找目标元素的索引
    left, right = 0, len(nums) - 1
    while left <= right:
        mid = (left + right) // 2
        if nums[mid] == target:
            break
        elif nums[mid] < target:
            left = mid + 1
        else:
            right = mid - 1

    # 如果找不到目标元素,则返回[-1, -1]
    if left > right:
        return [-1, -1]

    # 使用两个指针找到目标元素的第一个和最后一个位置
    first_pos, last_pos = mid, mid
    while first_pos > 0 and nums[first_pos - 1] == target:
        first_pos -= 1
    while last_pos < len(nums) - 1 and nums[last_pos + 1] == target:
        last_pos += 1

    return [first_pos, last_pos]

LeetCode 33. 搜索旋转排序数组

问题
给定一个已排序的数组,该数组被旋转了若干次,返回该数组中某个目标元素的位置。如果目标元素不存在,则返回-1。

思路分析
我们可以使用二分法算法来解决这个问题。首先,我们可以使用二分法算法找到数组的中点。然后,我们可以比较目标元素与数组的中点元素的值。如果目标元素等于数组的中点元素的值,则目标元素已被找到,算法停止。否则,我们需要确定目标元素是在数组的中点元素的左边还是右边。我们可以通过比较目标元素与数组的中点元素的左边和右边的元素的值来确定。如果目标元素小于数组的中点元素的左边元素的值,则目标元素一定在数组的中点元素的左边。否则,目标元素一定在数组的中点元素的右边。

代码实现

def search(nums, target):
    """
    :type nums: List[int]
    :type target: int
    :rtype: int
    """
    # 使用二分法查找目标元素的索引
    left, right = 0, len(nums) - 1
    while left <= right:
        mid = (left + right) // 2
        if nums[mid] == target:
            return mid

        # 判断目标元素是在数组的中点元素的左边还是右边
        if nums[left] <= nums[mid]:
            # 如果数组的中点元素在左边部分的最小值和最大值之间
            if nums[left] <= target < nums[mid]:
                right = mid - 1
            else:
                left = mid + 1
        else:
            # 如果数组的中点元素在右边部分的最小值和最大值之间
            if nums[mid] < target <= nums[right]:
                left = mid + 1
            else:
                right = mid - 1

    # 如果找不到目标元素,则返回-1
    return -1

总结

通过LeetCode中的这两个经典问题,我们对二分法算法有了更深入的理解。二分法算法是一种非常高效的搜索算法,它可以帮助我们在复杂度为O(logn)的时间内找到目标元素。掌握二分法算法对于任何程序员来说都是非常重要的,它可以帮助我们解决各种各样的问题,如查找、排序和计数等。