【LeetCode】陌陌面试-有序数组于其一个元素翻转后,判断一个数是否存在数组中,时间复杂度O(logn)

1.有序数组,判断一个数是否存在于数组中,时间复杂度O(logn)

解题思路:

二分法,在有序数组中,提高时间复杂度的一个方法。

代码:

def demo(nums, target):
    left,right=0,len(nums)-1
    while left <= right:
        mid = (left + right)/2
        if target < nums[mid]:
            right = mid - 1
        elif target > nums[mid]:
            left = mid + 1
        else:
            return True
    return False 

2.有序数组,从一个元素中翻转,判断一个数是否存在于数组中,时间复杂度O(logn)

例子:

[1, 2, 3, 4, 6, 7, 8, 10,11]  ,从4这个元素,左右翻转,[6, 7, 8, 10,11,1, 2, 3, 4] 

依然使用二分法,难点在于如何判断 target 在前半段还是后半段。对于无重复的数组[6, 7, 8, 10,1, 2, 3, 4],如果满足 A[begin] <= A[mid] ,即数组的第一个值小于中间值 6 < 11 ,那么可以断定前半段数组有序。如果不满足这个条件, 则说明后半段有序。因为把这个数组从中间分开后,一定至少有半个数组是有序的。然后再判断 target 是否在有序的半段中(这个很好判断),如果在,则相当于在有序数组中查找,很简单。如果不在有序的那半段,则一定在另外半段里。然后使用迭代即可把target找出。

def demo(nums, target):
    left,right=0,len(nums)-1
    while left <= right:
        mid = (left + right)/2
        # 判断mid是否为target,如果是,直接返回,如果不是,再判断target是在前半段还是后半段
        if nums[mid] == target:
            return mid
        # 如果前半段有序
        if nums[left] <= nums[mid]:
            # 判断target是否在前半段,如果在,则继续遍历前半段,如果不在,则继续遍历后半段
            if nums[left] <= target and target < nums[mid]:
                right = mid -1
            else:
                left = mid + 1
        # 后半段有序
        else:
            # 判断target是否在后半段,如果在,则继续遍历后半段,如果不在后半段,则继续遍历前半段
            if nums[mid] < target and target <= nums[right]:
                left = mid + 1
            else:
                right = mid - 1
    return -1

3.一个递增数组中,target出现的次数

力扣

输入: nums = [5,7,7,8,8,10], target = 8
输出: 2

解题思路:

排序数组中的搜索问题,首先想到 二分法 解决。

排序数组 nums 中的所有数字 targettarget 形成一个窗口,记窗口的 左 / 右边界 索引分别为 left 和 right ,分别对应窗口左边 / 右边的首个元素。

本题要求统计数字 target 的出现次数,可转化为:使用二分法分别找到 左边界left 和 右边界 right ,易得数字target 的数量为right−left−1 。

扫描二维码关注公众号,回复: 15668277 查看本文章
class Solution:
    def search(self, nums: [int], target: int) -> int:
        # 搜索右边界 right
        i, j = 0, len(nums) - 1
        while i <= j:
            m = (i + j) // 2
            if nums[m] <= target: i = m + 1
            else: j = m - 1
        right = i
        # 若数组中无 target ,则提前返回
        if j >= 0 and nums[j] != target: return 0
        # 搜索左边界 left
        i = 0
        while i <= j:
            m = (i + j) // 2
            if nums[m] < target: i = m + 1
            else: j = m - 1
        left = j
        return right - left - 1

猜你喜欢

转载自blog.csdn.net/pearl8899/article/details/126318693