2022.11.27

1、二分查找(leetcode[704,278,35])


二分算法思想就是设左右指针,慢慢向中间逼近,最后返回中间符合题意的部分。使用二分查找时要格外注意细节,比如while循环中判断语句,mid是否需要加减一。

注意要防止left+right相加过大导致(left+right)/2 溢出,一般可以使用left+(right-left)/2.


搜索一个元素情况---leetcode第704题 704. 二分查找 

题目:给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

首先这个题区间为[left,right],也就是两端闭。while(left<=right)也就是代码停止条件为left==right+1时。代入具体数字[3,2]可以看出,没有数大于3并且小于2,因此是合理的。如果判断条件为while(left<right),代入具体数字[2,2]可以看出,如果在这种情况下停止代码就会漏掉2。本题中mid加减一主要是因为区间是闭合的,我们已经知道此时mid不是题中想要的解,因此接下来就不需要再进行判断。

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

搜索边界时,口号中如果比较复杂难记,可以改成和第一题中相同模型,记得额外考虑边界。

搜索左边界--第一个错误的版本(278)  搜索插入位置(35结合)

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        if len(nums)==0:
            return -1
        left = 0
        right = len(nums)-1
        mid = left+(right-left)//2
        while(left<=right):
            if nums[mid]==target:
                right = mid-1  # 向左收缩
            elif nums[mid]>target:
                right = mid-1
            else:
                left = mid+1
            mid = left+(right-left)//2
        if left>=len(nums) or nums[left]!=target:
            return -1
        return left

增加判断条件是因为防止如下图所示超出边界(为啥第一个不用??) 

 搜索右边界

class Solution:
    def search(self, nums: List[int], target: int) -> int:
        if len(nums)==0:
            return -1
        left = 0
        right = len(nums)-1
        mid = left+(right-left)//2
        while(left<=right):
            if nums[mid]==target:
                left = mid+1  # 向右收缩
            elif nums[mid]>target:
                right = mid-1
            else:
                left = mid+1
            mid = left+(right-left)//2
        if right<0 or nums[right]!=target:
            return -1
        return right

2、双指针(leetcode[977,283,167,344,876,19])

设置左右指针

leetcode977--有序数组的平方

题目:给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

class Solution:
    def sortedSquares(self, nums: List[int]) -> List[int]:
        n = len(nums)
        result = [-1]*n
        i,j,pos = 0,n-1,n-1
        while(i<=j):
            if nums[i]*nums[i]>nums[j]*nums[j]:
                result[pos] = nums[i]*nums[i]
                i += 1
            else:
                result[pos] = nums[j]*nums[j]
                j -= 1
            pos -= 1
        return result

这个题的关键在于无论是正数还是负数,最大值的平方一定出现在左右两端,比如:

[1,2,3,4,5]----最大值平方25(右端点)

[-5,-4,-3,-2,-1]----最大值平方25(左端点)

[-5,-4,0,3,2]---最大值平方25(左端点)

因此只需要比较每次左右边界平方大小,将大的放到数组最尾端即可。

leetcode977---移动零

题目:给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。请注意 ,必须在不复制数组的情况下原地对数组进行操作。

class Solution:
    def moveZeroes(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        left = right =0
        while(right<len(nums)):
            if nums[right]!=0:
                nums[left],nums[right] = nums[right],nums[left]
                left += 1
            right += 1
        return nums

left指向的是已经处理好的序列的最右端,right指向的是未处理序列的最左端。右指针不断向右移动,每次右指针指向非零数,则将左右指针对应的数交换【也可以直接覆盖,最后用for循环对left及以后的赋值为0】,同时左指针右移。

leetcode167---两数之和 II - 输入有序数组

题目:给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列  ,请你从数组中找出满足相加之和等于目标数 target 的两个数

class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        i = 0
        j = len(numbers)-1
        while (i<j):
            if numbers[i]+numbers[j]==target:
                return [i+1,j+1]
            elif numbers[i]+numbers[j]<target:
                i=i+1
            else:
                j=j-1

初始时两个指针分别指向第一个元素位置和最后一个元素的位置。每次计算两个指针指向的两个元素之和,并和目标值比较。如果两个元素之和等于目标值,则发现了唯一解。如果两个元素之和小于目标值,则将左侧指针右移一位。如果两个元素之和大于目标值,则将右侧指针左移一位。移动指针之后,重复上述操作,直到找到答案。 这个题也可以用二分法【固定一个值,在剩余区间里找target-固定的值】。

leetcode344--反转字符串

题目:编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        left = 0
        right = len(s)-1
        while(left<right):
            s[left],s[right] = s[right],s[left]
            left += 1
            right -= 1
        return s

 leetcode876--链表的中间结点

题目:给定一个头结点为 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

class Solution:
    def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
        slow = head
        fast = head
        while(fast and fast.next):
            slow = slow.next
            fast = fast.next.next
        return slow

 经典链表快慢指针,慢指针走一步,快指针走两步。快指针走到最后时,慢指针走到一半。

 leetcode19-- 

题目:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

class Solution:
    def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
        dummy = ListNode(0, head)
        slow = dummy
        fast = head
        for i in range(n):
            fast = fast.next
        while(fast):
            slow = slow.next
            fast = fast.next
        slow.next = slow.next.next
        return dummy.next

 整体思路是让前面的指针先移动n步,之后前后指针共同移动直到前面的指针到尾部为止。这里注意链表常用技巧,设置哑节点dummy【不用特意考虑头节点】

3、其他题 

189. 轮转数组 

题目:给你一个数组,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        for i in range(k):
            nums.insert(0, nums.pop())
        return nums

先把最后面数字弹出来再插入到数组第一个位置

557. 反转字符串中的单词 III

题目:给定一个字符串 s ,你需要反转字符串中每个单词的字符顺序,同时仍保留空格和单词的初始顺序。

class Solution:
    def reverseWords(self, s: str) -> str:
        words = s.split(" ")
        result = ""
        for i in words:
            result += i[::-1]  # 从前到后,步长为-1----从后到前
            result += " "
        result = result[:-1]
        return result

 使用split函数先将每个单词分开然后对每个单独单词进行操作。最后一步result = result[:-1]是因为前面循环中多加了一个空格

| 序号 | 日期 | 说明 | | ---- | ----------- | ---- | | 1 | 2022.12.01 | | | 2 | 2022.12.02 | | | 3 | 2022.12.03 | | | 4 | 2022.12.04 | | | 5 | 2022.12.05 | | | 6 | 2022.12.06 | | | 7 | 2022.12.07 | | | 8 | 2022.12.08 | | | 9 | 2022.12.09 | | | 10 | 2022.12.10 | | | 11 | 2022.12.11 | | | 12 | 2022.12.12 | | | 13 | 2022.12.13 | | | 14 | 2022.12.14 | | | 15 | 2022.12.15 | | | 16 | 2022.12.16 | | | 17 | 2022.12.17 | | | 18 | 2022.12.18 | | | 19 | 2022.12.19 | | | 20 | 2022.12.20 | | | 21 | 2022.12.21 | | | 22 | 2022.12.22 | | | 23 | 2022.12.23 | | | 24 | 2022.12.24 | | | 25 | 2022.12.25 | | | 26 | 2022.12.26 | | | 27 | 2022.12.27 | | | 28 | 2022.12.28 | | | 29 | 2022.12.29 | | | 30 | 2022.12.30 | | | 31 | 2022.12.31 | | | 32 | 2023.01.01 | | | 33 | 2023.01.02 | | | 34 | 2023.01.03 | | | 35 | 2023.01.04 | | | 36 | 2023.01.05 | | | 37 | 2023.01.06 | | | 38 | 2023.01.07 | | | 39 | 2023.01.08 | | | 40 | 2023.01.09 | | | 41 | 2023.01.10 | | | 42 | 2023.01.11 | | | 43 | 2023.01.12 | | | 44 | 2023.01.13 | | | 45 | 2023.01.14 | | | 46 | 2023.01.15 | | | 47 | 2023.01.16 | | | 48 | 2023.01.17 | | | 49 | 2023.01.18 | | | 50 | 2023.01.19 | | | 51 | 2023.01.20 | | | 52 | 2023.01.21 | | | 53 | 2023.01.22 | | | 54 | 2023.01.23 | | | 55 | 2023.01.24 | | | 56 | 2023.01.25 | | | 57 | 2023.01.26 | | | 58 | 2023.01.27 | | | 59 | 2023.01.28 | | | 60 | 2023.01.29 | | | 61 | 2023.01.30 | | | 62 | 2023.01.31 | | | 63 | 2023.02.01 | | | 64 | 2023.02.02 | | | 65 | 2023.02.03 | | | 66 | 2023.02.04 | | | 67 | 2023.02.05 | | | 68 | 2023.02.06 | | | 69 | 2023.02.07 | | | 70 | 2023.02.08 | | | 71 | 2023.02.09 | | | 72 | 2023.02.10 | | | 73 | 2023.02.11 | | | 74 | 2023.02.12 | | | 75 | 2023.02.13 | | | 76 | 2023.02.14 | | | 77 | 2023.02.15 | | | 78 | 2023.02.16 | | | 79 | 2023.02.17 | | | 80 | 2023.02.18 | | | 81 | 2023.02.19 | | | 82 | 2023.02.20 | | | 83 | 2023.02.21 | | | 84 | 2023.02.22 | | | 85 | 2023.02.23 | | | 86 | 2023.02.24 | | | 87 | 2023.02.25 | | | 88 | 2023.02.26 | | | 89 | 2023.02.27 | | | 90 | 2023.02.28 | | | 91 | 2023.03.01 | | | 92 | 2023.03.02 | | | 93 | 2023.03.03 | | | 94 | 2023.03.04 | | | 95 | 2023.03.05 | | | 96 | 2023.03.06 | | | 97 | 2023.03.07 | | | 98 | 2023.03.08 | | | 99 | 2023.03.09 | | | 100 | 2023.03.10 | | | 101 | 2023.03.11 | | | 102 | 2023.03.12 | | | 103 | 2023.03.13 | | | 104 | 2023.03.14 | | | 105 | 2023.03.15 | | | 106 | 2023.03.16 | | | 107 | 2023.03.17 | | | 108 | 2023.03.18 | | | 109 | 2023.03.19 | | | 110 | 2023.03.20 | | | 111 | 2023.03.21 | | | 112 | 2023.03.22 | | | 113 | 2023.03.23 | | | 114 | 2023.03.24 | | | 115 | 2023.03.25 | |
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值