Leetcode 刷题 Binary Search Easy难度经验总结

[TOC]


刷了4道Binary Search  Easy难度的题

二叉搜索思想好想,难在边界的控制上,于是乎我就在思考能不能背下一个定式,遇到二分搜索的题目就套这个定式。

我做的第一道二叉搜索的题目就是一个很好的定式:

#744Find Smallest Letter Greater Than Target

Given a list of sorted characters letters containing only lowercase letters, and given a target letter target, find the smallest element in the list that is larger than the given target.

Letters also wrap around. For example, if the target is target = 'z' and letters = ['a', 'b'], the answer is 'a'.

Examples:

Input:
letters = ["c", "f", "j"]
target = "a"
Output: "c"

Input:
letters = ["c", "f", "j"]
target = "c"
Output: "f"

Input:
letters = ["c", "f", "j"]
target = "d"
Output: "f"

Input:
letters = ["c", "f", "j"]
target = "g"
Output: "j"

Input:
letters = ["c", "f", "j"]
target = "j"
Output: "c"

Input:
letters = ["c", "f", "j"]
target = "k"
Output: "c"

Note:

  1. letters has a length in range [2, 10000].
  2. letters consists of lowercase letters, and contains at least 2 unique letters.
  3. target is a lowercase letter.
class Solution(object):
    def nextGreatestLetter(self, letters, target):
        """
        :type letters: List[str]
        :type target: str
        :rtype: str
        """
        low = 0
        high = len(letters)
        while (low < high) :
            mid = low + (high - low) / 2
            if (letters[mid] <= target): 
                low = mid + 1
            else: high = mid
        
        return letters[low % len(letters)]
这里面的low,high都是指脚标
这个定式的特点是:
给定一个有序排列(可能有重复值,可能没有)的数组,和一个target

low的初始值指向第一个元素 ,本意是指脚标
high的初始值指向最后一个元素还往后移一个,本意是指脚标
 while(low<high):
       mid的公式恒久不变 mid= low +int((high -low)/2)       
       if (mid<=target):
              low=mid+1
      else: 
            high=mid
  return low 

return的时候,low和high必相等,但不一定等于mid
返回的low指向比target大的数中最小的那个数!(这个性质很好)


现在我们试试套用这个定式再做一道题:

34 Search for a Range

Given an array of integers sorted in ascending order, find the starting and ending position of a given target value.

Your algorithm's runtime complexity must be in the order of O(log n).

If the target is not found in the array, return [-1, -1].

For example,
Given [5, 7, 7, 8, 8, 10] and target value 8,
return [3, 4].

class Solution(object):
    def searchRange(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """
        
        if len(nums)==0:#空输入处理
            return [-1,-1]
      
        low = 0
        high = len(nums)

        while (low < high):
            mid = low + int((high - low) / 2)
            if (nums[mid] <= target):
                low = mid + 1
            else:
                high = mid


        start=low-1#target所在的位置,因为low是比target大的数中最小的一个
        end=low-1#target所在的位置,因为low是比target大的数中最小的一个

        if (nums[end] != target ):#target不存在于数组中
            return [-1,-1]
        else:#target存在于数组中

            while (start != 0 and nums[start] == nums[start - 1]):#看看start左边是不是还有一样的值
                start = start - 1

            return [start,end]
完美地套用了我们的定式,

最后的if -else分支是根据本题再做的逻辑补充


374.Guess Number Higher or Lower

We are playing the Guess Game. The game is as follows:

I pick a number from 1 to n. You have to guess which number I picked.

Every time you guess wrong, I'll tell you whether the number is higher or lower.

You call a pre-defined API guess(int num) which returns 3 possible results (-11, or 0):

-1 : My number is lower
 1 : My number is higher
 0 : Congrats! You got it!

Example:

n = 10, I pick 6.

Return 6.

# The guess API is already defined for you.
# @param num, your guess
# @return -1 if my number is lower, 1 if my number is higher, otherwise return 0
# def guess(num):

class Solution(object):
    def guessNumber(self, n):
        """
        :type n: int
        :rtype: int
        """
        low=1#Low index
        high=n+1#high index
        while (low<high):
            mid=low+int((high-low)/2)
            if (guess(mid)==1):#mid<=target
                   low=mid+1
            elif(guess(mid)==-1):
                   high =mid 
            elif(guess(mid)==0):
                return mid
        
            
        
                 

排序的数组不是nums参数的形式,而是给了一个参数n,对应数组1,2,....n

low在这里面还指向有序数组里最小的那个第一个数

high在这里还是指向 数组最后一个数还往后移一位

仍然符合定式


278First Bad Version

You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad.

Suppose you have n versions [1, 2, ..., n] and you want to find out the first bad one, which causes all the following ones to be bad.

You are given an API bool isBadVersion(version) which will return whether version is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API.

# The isBadVersion API is already defined for you.
# @param version, an integer
# @return a bool
# def isBadVersion(version):

class Solution(object):
    def firstBadVersion(self, n):
        """
        :type n: int
        :rtype: int
        """
        low=1#low_index
        high=n+1#high_index
        while(low<high):
            mid=low+int((high-low)/2)
            if(isBadVersion(mid)==True):
                    high=mid
            else:
                    low=mid+1
            
        return low
                 
        
            

因为现在比如对于 1, 2, 3这个数组

脚标low =1,high=4                                        类比可得应该return low 

并不是实际上的 low_index=0 ,high_index=3  return low-1

依然是定式的变形 


总结:

记住定式的套路(<= ,等啊不等啊什么的)

依据题意和实际情况改一下low,high的初始值

和return的值

这个套路目前为止没失败过


难度升级:

Leetcode153Find Minimum in Rotated Sorted Array

Medium难度,剑指OFFER面试题8(旋转数组的最小数字)

我的解法(根据剑指OFFER的C++改编的Python解法)

Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

Find the minimum element.

You may assume no duplicate exists in the array.


class Solution(object):
    def findMin(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(nums)==0:
            return 0
        i=0#指向前部分递增序列第一个数的指针
        j=len(nums)-1#指向后部分递增序列最后一个数的指针
        indexmid=i#当第一个数小于最后一个数的时候,证明该数组没有旋转过,返回indexmid,所以把indexmid赋初值为i
        
        while(nums[i]>=nums[j]):
            
            if (j-i)==1:
                indexmid=j
                break
            else:
                indexmid=(i+j)/2
                if nums[i]==nums[j] and nums[indexmid]==nums[i]:#数组的第一个数和最后一个数和中间的数一样,即没有办法通过nums[mid]的大小判断它在哪个部分
                        result=nums[i]#result保存当前的最小值
                        for pointer in range(i+1,j+1):
                            if result>nums[pointer]:    
                                result=nums[pointer]
                        return result
                    
                if  nums[indexmid]>=nums[i]:#mid处于前部分增的序列里
                     i=indexmid
                elif nums[indexmid]<nums[j]:#mid处于后部分增的序列里
                     j=indexmid
            
        return nums[indexmid]
           
        
                        
考点:测试用例设计的完善与否,考虑以下几种特殊情况:
->旋转0次即没有旋转的数组:0,1,2,3,4,5,6

->[1,0,1,1,1][1,1,1,0,1]这种start=mid=end的情况

难点:我以前只知道二分搜索可以用在有序搜索上,但以前遇到的都是全局有序,这种局部有序的问题没有思考过!局部有序也是有序,也可以用二分法(可能需要配合On的遍历,如例题)


153 Find Minimum in Rotated Sorted Array
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值