Leetcode刷题-二分查找

灵神的二分视频:二分查找 红蓝染色法_哔哩哔哩_bilibili

34

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        right = len(nums) - 1
        left = 0
        res = [-1,-1]
        mid = int((right + left)/2)
        while right >= left:
            if nums[mid] < target:
                left = mid + 1
                mid = int((right + left)/2)
                continue
            if nums[mid] > target:
                right = mid - 1
                mid = int((right + left)/2)
                continue
            if nums[mid] == target:
                res[0] = mid
                res[1] = mid
                break
        if res[0] != -1:
            right = mid + 1
            left = mid - 1
            while right >= 0 and right < len(nums):
                if nums[right] != target:
                    break
                res[1] = right
                right += 1
            while left >= 0:
                if nums[left] != target:
                    break
                res[0] = left
                left -= 1
        return res

        

35

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

704

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

744

class Solution:
    def nextGreatestLetter(self, letters: List[str], target: str) -> str:
        left = -1
        right = len(letters)
        while left + 1 < right:
            mid = (left + right) // 2
            if letters[mid] < chr(ord(target) + 1):
                left = mid
            else:
                right = mid
        if right >= 0 and right < len(letters):
            return letters[right]
        else:
            return letters[0]
        

2529

class Solution:
    def maximumCount(self, nums: List[int]) -> int:
        left = -1
        right = len(nums)
        pos = 0
        neg = 0
        while left + 1 < right:
            mid = (left + right) // 2
            if nums[mid] < 1:
                left = mid
            else:
                right = mid
        pos = len(nums) - right
        left = -1
        right = len(nums)
        while left + 1 < right:
            mid = (left + right) // 2
            if nums[mid] < 0:
                left = mid
            else:
                right = mid
        neg = right
        return max(pos,neg)

1385

class Solution:
    def findTheDistanceValue(self, arr1: List[int], arr2: List[int], d: int) -> int:
        arr2.sort()
        res = 0
        for taget in arr1:
            left = -1
            right = len(arr2)
            while left + 1 < right:
                mid = (left + right) // 2
                if arr2[mid] + d < taget:
                    left = mid
                else:
                    right = mid
            if right == len(arr2) or arr2[right] > taget + d:
                res += 1
        return res    
        

        

1385

     先将potions列表排序,保证它是一个单调列表。然后遍历每一个咒语,找到刚好满足success条件的位置,即求出当前咒语和药水的成功对数。

class Solution:
    def successfulPairs(self, spells: List[int], potions: List[int], success: int) -> List[int]:
        potions.sort()
        res = []
        for i in spells:
            left = -1
            right = len(potions)
            
            while left + 1 < right:
                mid = (left + right) // 2
                if i * potions[mid] < success:
                    left = mid
                else:
                    right = mid

            res.append(len(potions)-right)
            
        return res

        

2389

class Solution:
    def answerQueries(self, nums: List[int], queries: List[int]) -> List[int]:
        ans = []
        nums.sort()
        for j in range(1,len(nums)):
            nums[j] += nums[j-1]
        print(nums)
        for i in queries:
            left = -1
            right = len(nums)
            while left + 1 < right:
                mid = (left + right) // 2
                if nums[mid] < i + 1:
                    left = mid
                else:
                    right = mid
            ans.append(right)
        return ans

        

1170

使用二分查找找到刚好比queries中统计值大1的位置,再用words的长度减去即为答案。

class Solution:
    def numSmallerByFrequency(self, queries: List[str], words: List[str]) -> List[int]:
        q = []
        w = []
        for i in words:
            a = min(i)
            w.append(i.count(a,0,len(i)))
        for j in queries:
            b = min(j)
            q.append(j.count(b,0,len(j)))
        w.sort()
        res = []
        for k in q:
            left = -1
            right = len(w)
            while left + 1 < right:
                mid = (left + right) // 2
                if w[mid] < k + 1:
                    left = mid
                else:
                    right = mid
            res.append(len(w) - right)
        return res
        

        

2080

先记录每个数字出现的位置,再用二分查找找出满足的位置,先找左端,再找右端。

class RangeFreqQuery:

    def __init__(self, arr: List[int]):
        pos = defaultdict(list)
        for i, x in enumerate(arr):
            pos[x].append(i)
        self.pos = pos

    def query(self, left: int, right: int, value: int) -> int:
        a = self.pos[value]
        # a.sort()
        lf = -1
        lr = len(a)
        while lf + 1 < lr:
            mid = (lf + lr) // 2
            if a[mid] < left:
                lf = mid
            else:
                lr = mid
        res = 0
        res += lr
        lf = -1
        lr = len(a)
        while lf + 1 < lr:
            mid = (lf + lr) // 2
            if a[mid] < right + 1:
                lf = mid
            else:
                lr = mid
        res = lr - res
        return res

        


# Your RangeFreqQuery object will be instantiated and called as such:
# obj = RangeFreqQuery(arr)
# param_1 = obj.query(left,right,value)

2563

        排序,然后进行二分查找。排序后顺序可能会混乱,题目要求的是下标 i < j。但是经过分析,我们可以发现,如果使用暴力做法,那么nums[j] 再整个过程中,和除了他自己本身的数都进行了一次数对判断(即nums[j] + 任意非自己的数)。 假设数对(i,j),i < j 满足nums[i] + nums[j] >= lower && nums[i] + nums[j] <= upper,那么数对(j,i)也满足,所以在结果上这两个数组是等价的,但由于题目要求只要(i,j),所以取其中一半即可,也就是我们可以忽略对原数组排序后下标的改变,保证只计入(i,j)或者(j,i)其中一种到答案中即可。所以我们可以设置每一次二分查找的区间为[ 0 , j - 1] (我这里采用的是开区间写法,所以是 [ 0 , j ]),这样就可以保证只计入(i,j)或者(j,i)。

class Solution:
    def countFairPairs(self, nums: List[int], lower: int, upper: int) -> int:
        res = 0
        n = nums
        n.sort()
        for i in range(len(n)):
            x = n[i]
            left = -1
            right = i
            while left + 1 < right:
                mid = (left + right) // 2
                if n[mid] + x < lower:
                    left = mid
                else:
                    right = mid
            p1 = right
            left = -1
            right = i
            while left + 1 < right:
                mid = (left + right) // 2
                if n[mid] + x < upper + 1:
                    left = mid
                else:
                    right = mid
            res += (right - p1)
        return res



        

2856

class Solution:
    def minLengthAfterRemovals(self, nums: List[int]) -> int:
        x = nums[len(nums) // 2]
        left = -1
        right = len(nums)
        while left + 1 < right:
            mid = (left + right) // 2
            if nums[mid] < x:
                left = mid
            else:
                right = mid
        p1 = right

        left = -1
        right = len(nums)
        while left + 1 < right:
            mid = (left + right) // 2
            if nums[mid] < x + 1:
                left = mid
            else:
                right = mid
        res = right - p1

        return max(res * 2 - len(nums), len(nums) % 2)        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YoloMari

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值