leetcode学习第5日——35_搜索插入位置(两种二分法与暴力破解法)

#!D:\softwares\anaconda python
# -*- coding: utf-8 -*-
# @Time : 2020/12/7 15:17
# @Author : weweaq
# @Site : 
# @File : 35_搜索插入位置.py
# @Software: PyCharm

from typing import List


class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums)
        while left < right:
            middle = (left + right) // 2
            if target == nums[middle]:
                return middle
            elif target > nums[middle]:
                left = middle + 1
            else:
                right = middle
        return right


solution = Solution()
print(solution.searchInsert([1,3,5,6], 10))

""" 暴力解法,遍历并进行判断,基础!
普通: 
    def searchInsert(self, nums: List[int], target: int) -> int:
        for num in nums:
            if num >= target:
                return nums.index(num)
        return len(nums)
较好: 要在二分查找的过程中,保持不变量,这也就是「循环不变量」,所谓循环不变量,是指循环中一直要保证为真的量
这个二分查找中,保持左闭右闭的区间,所以循环不变量为[left, right], 左或者右需要为 middle-1 或者 middle+1
class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums) - 1
        while left <= right:  # 此处如果缺失等于号,就会丢失 【a,a】这个区间,处理target小于Min(nums)或者大于max(nums)时,
                              # 会出错,提前跳出 while ,返回错误的 right 
            middle = (left + right) // 2
            if target == nums[middle]:
                return middle
            elif target > nums[middle]:
                left = middle + 1
            else:
                right = middle - 1
        return right+1
        
这个二分查找中,保持左闭右开的区间,所以循环不变量为[left, right), 左需要为 middle+1,右需要为 middle
class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        left = 0
        right = len(nums)  #  因为要保持循环不变量,这里一开始得是 len(nums), WCNMDP, 我看了半个多小时才发现这里的不同,一直都
                           # 以为这里和上面一样不需要改变 是 right = len(nums) - 1 ,所以结果一直都不对,纠结了贼长时间!
        while left < right:
            middle = (left + right) // 2
            if target == nums[middle]:
                return middle
            elif target > nums[middle]:
                left = middle + 1
            else:
                right = middle
        return right
重点:在左闭右开区间的二分法中,我感觉二分法确实很神奇,他其实对于 target 的比较,并不是会与两边的 nums[left] or nums[right] 有关
,它是一直都与 nums[median] 进行比较(即只与中位值进行比较,不与边界值进行比较),所以 left 和 right 索引在必要时是可以超出数组
长度的界限,我觉得很有意思!

注意:第二个二分查找中,保持左闭右开的区间,所以循环不变量为[left, right),在初始化时就要满足这个条件,right = len(nums)!!

"""

"""
以下供单链表使用:
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = None


class LinkList:
    def __init__(self):
        self.head_node = self.tail = self.head = None

    def initList(self, data):
        self.head = ListNode(data[0])
        self.tail = self.head
        for i in data[1:]:
            self.tail.next = ListNode(i)
            self.tail = self.tail.next
        return self.head

    def printList(self, head):
        if head is None:
            return
        self.head_node = head
        while self.head_node is not None:
            if self.head_node.next is not None:
                print(self.head_node.val, end=' => ')
            else:
                print(self.head_node.val)
            self.head_node = self.head_node.next
"""

上一篇:二分法(折半查找)


下一篇:二分法实现开平方(JAVA实现)