Day 1 数组 二分:35.搜索插入, 34. 排序数组第一和最后, 69. 平方根, LC 367. 有效完全平方数

LC 35.搜索插入位置

  • 思路
    • example: [1,3,5], target = 0,1,2,3,4,5,6
      • nums = [5], target = 5, ans = 0
      • nums = [5], target = 6, ans = 1
      • nums = [5], target = 4, ans = 0
    • 已排好序,无重复元素
    • 类似 “插入位置:第1个>=target的位置”,答案范围:0,1,..., n
    • 二分模板2,左闭右开, left = 0, right = n (NOT n-1), while left < right, <, >=; quit when left == right
  • 复杂度. 时间:O(log n), 空间: O(1)
class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        n = len(nums)
        left, right = 0, n
        while left < right: # [left, right)
            mid = left + (right - left) // 2
            if nums[mid] < target:
                left = mid + 1
            else: # nums[mid] >= target
                right = mid
        return left # or right 
  • 左闭右闭思路更好理解。
    • [left, right]表示答案的存在范围,初始left = 0, right = n。
    • mid是向下取整的“一半”
    • nums[mid] < target:插入位置必在[mid+1, right] (左半部不可能包含答案)
    • nums[mid] >= target: 插入位置必在[left, mid], 注意mid仍有可能是答案 (mid右边不可能包含答案)
    • 终止条件:left == right, 这个时候mid = left = right, 如果nums[mid] >= target,指针不会有变化,死循环。所以left == right时就停止。
      • 最后left == right是由3个元素或2个元素变为1个元素。
        -最后return left (或 right)
  • 左闭右闭 (用这个版本,可拓展)
    • 类似 “插入位置:第1个>=target的位置”,答案范围:0,1,..., n
class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        n = len(nums)
        left, right = 0, n-1
        while left <= right:
            mid = left + (right - left) // 2
            if nums[mid] == target:
                return mid 
            elif nums[mid] < target:
                left = mid + 1
            else:
                right = mid - 1
        return left  # left \in [0,...,n]
  • 下面的版本可针对有重复元素的情况。更一般。
    • bisect_left
class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        n = len(nums)
        left, right = 0, n-1 
        while left <= right:
            mid = left + (right - left) // 2
            if nums[mid] < target:
                left = mid + 1
            else:
                right = mid - 1
        return left # could be n 

34. 排序数组中查找第一个和最后一个位置

  • 思路
    • example
    • 已排好序,有重复元素
    • 第1个==位置,最后一个==位置
    • 二分模板1,左闭右闭, left = 0, right = n-1, while left <= right, ==, >, <; quit when left > right
      • type = 'first' or 'last'
    • type = 'first'
      • nums[mid] > target: 答案在[left, mid-1]
      • nums[mid] < target: 答案在[mid+1, right]
      • nums[mid] == target: 答案在[left, mid], 但是第一个等于target的位置可能在更左边。 为方便,直接去[left, mid-1]找可能的答案。
      • while left <= right:
      • 最后一步left==right时,判断最可能的答案 (可能越界:n)(return left)。
    • type = 'last'
      • nums[mid] > target: 答案在[left, mid-1]
      • nums[mid] < target: 答案在[mid+1, right]
      • nums[mid] == target: 答案在[left, mid], 但是最后一个等于target的位置可能在更右边。 为方便,直接去[mid+1, right]找可能的答案。
      • while left <= right:
      • 最后一步left==right时,判断最可能的答案 (可能越界:-1)(return right)。
  • 复杂度. 时间:O(log n), 空间: O(1)
class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        n = len(nums)
        def BinarySearch(left, right, type):
            while left <= right:
                mid = left + (right - left) // 2
                if nums[mid] == target and type == 'first':
                    right = mid - 1
                elif nums[mid] > target: # both cases
                    right = mid - 1
                else: # 'first': < target; 'last': <= target
                    left = mid + 1
            return left if type == 'first' else right 
        idx1 = BinarySearch(0, n-1, 'first')
        idx2 = BinarySearch(0, n-1, 'last')
        if idx1 > idx2: return [-1, -1]
        return [idx1, idx2]
  • 另一个思路
    • 数组前面加-\infty,后面加\infty.
    • 第一个 >=target 位置: idx1;答案在[0,...,n]中; 左闭右闭二分模板2:while left < right。
    • 第一个 >target 位置: idx2,答案在[0,...,n]中; 左闭右闭二分模板2:while left < right。
    • 注意要判断idx1是否等于n或者对应数字是否等于target。
    • idx2 -= 1得到最后一个<= target 位置。
    • mid = left + (right - left) // 2,向下取整(可能等于left),所以二分写法如果出现left = mid,可能会死循环。
  • 用这个版本
class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        def binarySearch_first(nums, target): # search the first position >= target 
            n = len(nums)
            left, right = 0, n-1 
            while left <= right: 
                mid = left + (right - left) // 2
                if nums[mid] < target:
                    left = mid + 1
                elif nums[mid] > target:
                    right = mid - 1 
                else: # nums[mid] == target 
                    right = mid - 1
            # now left > right, left in [0,...,n]
            return left 
        def binarySearch_last(nums, target): # search the last position >= target 
            n = len(nums)
            left, right = 0, n-1
            while left <= right:
                mid = left + (right - left) // 2
                if nums[mid] < target:
                    left = mid + 1
                elif nums[mid] > target: 
                    right = mid - 1
                else: # == 
                    left = mid + 1
            # now right > left, right in [-1,0,...,n-1]
            return right 
        idx1 = binarySearch_first(nums, target)
        if idx1 == n or nums[idx1] != target:
            return [-1, -1]
        idx2 = binarySearch_last(nums, target) 
        return [idx1, idx2]
class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        def binarySearch_first(nums, target): # 1st index, >= target
            n = len(nums)
            left, right = 0, n-1 
            while left <= right:
                mid = left + (right - left) // 2
                if nums[mid] < target:
                    left = mid + 1
                elif nums[mid] >= target:
                    right = mid -1 
            return left  
        def binarySearch_last(nums, target): # last index, >= target 
            n = len(nums)
            left, right = 0, n-1 
            while left <= right:
                mid = left + (right - left) // 2
                if nums[mid] <= target:
                    left = mid + 1
                elif nums[mid] > target:
                    right = mid -1 
            return right  
        n = len(nums)
        idx1 = binarySearch_first(nums, target) 
        if idx1 == n or nums[idx1] != target: 
            return [-1, -1] 
        idx2 = binarySearch_last(nums, target) 
        return [idx1, idx2] 

LC 69: 平方根

  • 思路
    • example
    • largest k such that k*k <= x
    • 二分模板1,左闭右闭, <=, >
  • 复杂度. 时间:O(log n), 空间: O(1)
class Solution:
    def mySqrt(self, x: int) -> int:
        left, right = 0, x
        res = 0
        while left <= right:
            mid = left + (right - left) // 2
            num = mid * mid
            if num <= x:
                res = mid
                left = mid + 1
            else: # num > x
                right = mid - 1
        return res
  • 这个版本也可以
class Solution:
    def mySqrt(self, x: int) -> int:
        left, right = 0, x 
        while left <= right:
            mid = left + (right - left) // 2
            mid2 = mid * mid 
            if mid2 == x:
                return mid 
            elif mid2 < x:
                left = mid + 1
            else: # mid2 > x 
                right = mid - 1
        return right 

LC 367. 有效完全平方数

  • 思路
    • example
    • find k such that k*k == num
    • 二分模板1,左闭右闭, ==, <, >
  • 复杂度. 时间:O(log n), 空间: O(1)
class Solution:
    def isPerfectSquare(self, num: int) -> bool:
        left, right = 0, num
        while left <= right:
            mid = left + (right - left) // 2
            square = mid * mid
            if square == num:
                return True
            elif square < num:
                left = mid + 1
            else:
                right = mid - 1
        return False
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352

推荐阅读更多精彩内容