网站Logo 夕拾朝花

python代码随想录 冲刺训练营

miubai
9
2025-10-06

python代码随想录 冲刺训练营

每天保证至少两小时

day1--9.17

704. 二分查找

  1. 解析:

  2. 题解:

     ​
  3. 总结: xxx

27. 移除元素

  1. 解析:https://programmercarl.com/0027.%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE

  2. 题解:

     class Solution:
         def removeElement(self, nums: List[int], val: int) -> int:
             # 移除元素 快慢指针法
             slowIndex = 0
             for fastIndex in range(0, len(nums)):
                 if nums[fastIndex] != val:
                     nums[slowIndex] = nums[fastIndex]
                     slowIndex += 1
             return slowIndex
  3. 总结:

    • 本题,想到用双指针处理问题,但是所用的指针是头尾指针,相对来说时间复杂度比暴力低一些,而且各项特殊情况不好进行处理。

    • 使用快慢指针,则不会存在特殊数组处理的问题。

    • 此类问题核心在于是数组移动,将需要的值移动,不需要的丢弃。此时通过控制双指针的移动,来剔除特定值。碰到无用的值,slow指针不动,通过后移fast指针,剔除该值。遇到有用的值,再将fast所指向的值赋值给slow指针所指向的位置,此时slow、fast同步后移。以此类推。

    • "双指针法(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组、链表、字符串等操作的面试题,都使用双指针法。"

977. 有序数组的平方

  1. 解析:https://programmercarl.com/0977.%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E5%B9%B3%E6%96%B9.html

  2. 题解:

     class Solution:
         def sortedSquares(self, nums: List[int]) -> None:
             for i in range(0, len(nums)):
                 nums[i] *= nums[i]
             nums.sort()
             print(nums)
         
         # 方法二 双指针 + 反转列表
         def sortedSquares(self, nums: List[int]) -> List[int]:
             res = []
             first = 0
             last = len(nums) - 1
             for i in range(0, len(nums)):
                 if nums[first] * nums[first] >= nums[last] * nums[last]:
                     res.append(nums[first] * nums[first])
                     first += 1
                 else:
                     res.append(nums[last] * nums[last])
                     last -= 1
             res.reverse()
             return res
  3. 总结:

    • 本题相对好过,进一步优化主要在于时间复杂度上,这里要记住常用算法的时间复杂度:快排是O(nlgn)

    • 双指针的用法:由于nums是有序的,而且nums中存在负数,那么平方后最大的数,应该在nums的两端,而非中间。因此每次取最大的数存入res中,最后将res进行反转即可。

day2---9.18

209. 长度最小的子数组

  1. 解析:

  2. 题解:

     #解法一:暴力双循环,会超时
     ​
     #解法二:快慢指针,卡哥这边叫做滑动窗口,更形象
     class Solution:
         def minSubArrayLen(self, target: int, nums: List[int]) -> int:
             sum = 0
             res = len(nums) + 1
             fastIndex = 0
             slowIndes = 0
             while fastIndex < len(nums):    # 借助连续条件,找到第一个target后,记录res,后移slow,sum减去slow的值,fast继续前移,直到末尾
                 sum += nums[fastIndex]
                 while sum >= target and slowIndes <= fastIndex:
                     res = min(res, fastIndex - slowIndes + 1)
                     sum -= nums[slowIndes]
                     slowIndes += 1
                 fastIndex += 1
             if res > len(nums):
                 return 0
             return res
         
  3. 总结

    • 题目阅读:leetcode题干对于子数组的说明进行了隐藏,鼠标移动至标蓝子数组,既有相关说明。本题重要条件即连续。

    • 利用连续条件,不断调整窗口,找到最小的窗口,使其满足窗口内所有元素之和大于或等于target即可。

59. 螺旋矩阵 II

  1. 解析

  2. 题解:

     class Solution:
         def generateMatrix(self, n: int) -> List[List[int]]:
             res = [[0] * n for _ in range(n)]
             count = 1
             startRow, startClow = 0, 0  # 控制每一圈起始位置
             loop = n // 2
             while loop > 0:
                 row = startRow
                 clow = startClow
                 while clow < (n - 1 - startClow):   # 左 -> 右
                     res[row][clow] = count
                     count += 1
                     clow += 1
     ​
                 while row < (n - 1 - startRow): # 上 -> 下
                     res[row][clow] = count
                     count += 1
                     row += 1
     ​
                 while clow > startClow: # 右 -> 左
                     res[row][clow] = count
                     count += 1
                     clow -= 1
     ​
                 while row > startRow:
                     res[row][clow] = count
                     count += 1
                     row -= 1
     ​
                 startRow += 1
                 startClow += 1
                 loop -= 1
                 
             if (n % 2) != 0:    # 奇数,处理中心点
                 res[startRow][startClow] = count
             return res
  3. 总结:

    • 本题考验边界处理能力、中心点处理能力,主要考察模拟解决现实问题的能力。

    • 本题两次碰壁,其一在于每次循环起点的处理上,仅想通过一个变量n来控制,显然是不现实的,的。包括现在用变量n和starRow、starClow控制边界,对于代码可读性,还存在可以改进的空间。这里可以再多设置几个变量,如left、right、top、bottom,使边界更加明确,且代码更容易读懂;其二在于对奇数中心点问题的处理上,特殊问题特殊处理,总想着在while循环中直接完成,这总导致索引超限。

    • 收获:其一,适当的增加变量,替换判断条件的每一次运算,可以增强代码可读性;其二,特殊问题,特殊处理,剥离特殊与一般;其三,写代码之前,务必提前理清思路,针对题解等现实问题,先行根据样例进行模拟,确保代码在编写之前,思路不存在问题。

  4. 本题模拟过程如下图 image-20250924201719131

day3---9.24

203. 移除链表元素

  1. 解析:https://programmercarl.com/0203.%E7%A7%BB%E9%99%A4%E9%93%BE%E8%A1%A8%E5%85%83%E7%B4%A0.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE

  2. 题解:

     # Definition for singly-linked list.
     # class ListNode:
     #     def __init__(self, val=0, next=None):
     #         self.val = val
     #         self.next = next
     class Solution:
         def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
             """'移除链表中,list.val=val的值,利用虚拟头节点进行处理"""
             dummyHead = ListNode()
             dummyHead.next = head
             prev = dummyHead
             cur = prev.next
             while cur is not None:
                 """进行删除"""
                 if cur.val == val:
                     prev.next = cur.next
                     cur = prev.next
                     continue
                 prev = prev.next
                 cur = prev.next
             return dummyHead.next
     ​
  3. 总结:

    • 对于链表问题,需要善用虚拟头节点

707. 设计链表

  1. 解析:https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE

  2. 题解:

     class LinkNodes:
         def __init__(self, val=-1, next=None):
             self.val = val
             self.next = next
     ​
     ​
     class MyLinkedList:
     ​
         def __init__(self):
             self.dummyHead = LinkNodes()
             self.size = 0
     ​
         def get(self, index: int) -> int:
             """获取链表中下标为index的节点的值"""
             if index >= self.size:
                 return -1
             cur = self.dummyHead.next
             while index > 0 and cur is not None:
                 cur = cur.next
                 index -= 1
             return cur.val
     ​
         def addAtHead(self, val: int) -> None:
             """插入头节点"""
             cur = LinkNodes(val, self.dummyHead.next)
             self.dummyHead.next = cur
             self.size += 1
     ​
         def addAtTail(self, val: int) -> None:
             """尾部插入节点"""
             cur = self.dummyHead
             while cur.next is not None:
                 cur = cur.next
             cur.next = LinkNodes(val, cur.next)
             self.size += 1
     ​
         def addAtIndex(self, index: int, val: int) -> None:
             """插入某个节点之前"""
             if index > self.size:
                 return
             if index == self.size:
                 self.addAtTail(val)
                 return
     ​
             cur = self.dummyHead
             while index > 0 and cur is not None:
                 cur = cur.next
                 index -= 1
             new_node = LinkNodes(val, cur.next)
             cur.next = new_node
             self.size += 1
     ​
         def deleteAtIndex(self, index: int) -> None:
             """删除链表中的某一个节点"""
             if index >= self.size:
                 return
             cur = self.dummyHead
             while index > 0 and cur is not None:
                 cur = cur.next
                 index -= 1
     ​
             cur.next = cur.next.next
             self.size -= 1
     ​
     # Your MyLinkedList object will be instantiated and called as such:
     # obj = MyLinkedList()
     # param_1 = obj.get(index)
     # obj.addAtHead(val)
     # obj.addAtTail(val)
     # obj.addAtIndex(index,val)
     # obj.deleteAtIndex(index)
  3. 总结:

    • 处理链表题时,一定要想清楚到底是带虚拟头节点,还不不带虚拟头节点,对链表的所有操作要保持一致性,否则会导致编写代码后一团乱麻。

    • 编写测试样例时,若涉及到多功能的函数(如本题),一定要尽量依据题目中函数,这样做一是减少编写代码工作量和重复性工作;二是本身函数中存在联调,单个函数满足要求,不一定能确保多个函数联调时功能执行正常。

206. 反转链表

  1. 解析:https://programmercarl.com/0206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%88%E6%9C%AC

  2. 题解:

     # Definition for singly-linked list.
     # class ListNode:
     #     def __init__(self, val=0, next=None):
     #         self.val = val
     #         self.next = next
     class Solution:
         def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
             if head is None:
                 return None
             res = ListNode()
             cur = head
             while cur is not None:
                 tmp = cur
                 cur = cur.next
                 tmp.next = res.next
                 res.next = tmp
     ​
             return res.next
     ​
  3. 总结:

    • 没什么难度~

    • 反转链表问题转换为头插法,每次遍历一个节点,将该节点插入res的头节点即可完成反转

    • 卡哥使用的双指针法也非常有意思,使用prev和cur两个指针,每次遍历将cur.next指向prev,然后cur借用temp移动至原链表下一个节点,如此往复循环。此方法相较本文更加节省空间。

day4---10.02

24. 两两交换链表中的节点

  1. 解析:

  2. 题解:

    class ListNode:
             def __init__(self, val=0, next=None):
                 self.val = val
                 self.next = next
         class Solution:
             def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
                 """使用递归完成链表节点两两交换"""
                 if head is None or head.next is None:
                     return head
                 prev = head
                 cur = head.next
                 next = head.next.next
         
                 head = cur
                 cur.next = prev
                 prev.next = self.swapPairs(next)
         
                 return head
             
             class Solution:
             def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
                 """使用迭代法完成链表节点两两交换"""
                 if head is None or head.next is None:
                     return head
                 prev = head
                 cur = prev.next
                 next = cur.next
         
                 head = cur
                 while prev is not None and cur is not None:
                     cur.next = prev
                     if next is None or next.next is None:
                         prev.next = next
                         return head
                     else:
                         prev.next = next.next
         
                     prev = next
                     cur = prev.next
                     next = cur.next
         
                 return head
  3. 总结:

    • 本题处理起来还不熟练,主要在两点,其一是递归处理,特别返回值这块儿存在问题;其二是问题思考方式,交换prev和cur还是交换cur和next,两种不同的思考方式,代码编写逻辑也不一样,故代码编写前一定要思量好。

    • 除了递归外,迭代也可以做,练习一下。

19. 删除链表的倒数第 N 个结点

  1. 解析:

  2. 题解:

    # Definition for singly-linked list.
    # class ListNode:
    #     def __init__(self, val=0, next=None):
    #         self.val = val
    #         self.next = next
    class Solution:
        def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
            """
            本题我想到两种方法,其一,新建一个链表,正数第len(head) - N 个不接入新链表(递归?);其二,利用栈,删除倒数第N个
            1.链表全部入栈
            2.节点弹出,同时n--,当n==1时,不进行记录
            3.弹出节点通过头插法建立新链表
            4.返回新链表
            """
            if head is None:
                return None
    
            dummy_head = ListNode()
            stack = []
            while head is not None:
                stack.append(head)
                head = head.next
    
            cur = dummy_head
            while len(stack) != 0:
                if n != 1:
                    """如果n != 1 则直接出栈,并通过头插法构建新链表"""
                    stack[-1].next = cur.next
                    cur.next = stack[-1]
                    stack.pop()
                else:
                    stack.pop()
                n -= 1
            return dummy_head.next
        
    
    class Solution:
    	def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
            
        """
        1.fast前进n+1
        2.fast、slow一起前进,直至fast=None
        3.删除slow.next指向的节点
        """
        if head is None or n <= 0:
            return None
        dummy_head = ListNode(-1, head)
        slow = dummy_head
        fast = dummy_head
    
        while n >= 0 and fast is not None:
            fast = fast.next
            n = n - 1
    
            if n >= 0 and fast is None: # 处理超越链表长度情况
                return None
    
            while fast is not None:
                slow = slow.next
                fast = fast.next
                slow.next = slow.next.next  # 要删除的节点在fast和slow之间
    
                return dummy_head.next
  3. 总结:

    • 一次AC~

    • 此类题,看到就想到对栈的用法,编写过程中存在问题,stack=[]这里和C/C++不一样,要记得python中列表是动态类型的,可以存储任何值,如果要注解其类型(类似C/C++中声明变量可以参考如下方式:stack: List[ListNode] = []

    • 卡哥这里采用的双指针,较本文更加节省空间和时间,思路同数组中的移除元素,采用快慢指针进行处理。

面试题 02.07. 链表相交

  1. 解析:https://programmercarl.com/%E9%9D%A2%E8%AF%95%E9%A2%9802.07.%E9%93%BE%E8%A1%A8%E7%9B%B8%E4%BA%A4.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%88%E6%9C%AC

  2. 题解:

    # Definition for singly-linked list.
    # class ListNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.next = None
    
    class Solution:
    
        def getLinkListLen(self, head: ListNode) -> int:
            """求链表长度"""
            if head is None:
                return 0
    
            cur = head
            res = 0
            while cur is not None:
                res += 1
                cur = cur.next
            return res
    
        def movePoint(self, head:ListNode, count) -> ListNode:
            if head is None or count == 0:
                return head
            cur = head
            while count > 0 and cur is not None:
                count -= 1
                cur = cur.next
            return cur
    
        def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
            """
            思路:先对齐,AB长短不一样,若相交,则AB长度之差则为需要对齐而移动的距离
            1.求AB长度,及长度差值d,假设B比A长
            2.长的链表(B),其指针先走d步,对齐AB指针位置
            3.AB指针同步移动,若AB指针指向地址一致,即为交点
            4.若AB遍历完了,还没有相交,则返回null
            """
            if headA is None or headB is None:
                return None
            len_A = self.getLinkListLen(headA)
            len_B = self.getLinkListLen(headB)
    
            curA, curB = headA, headB
            if len_A > len_B:   # 使AB指针离交点距离一样
                curA = self.movePoint(curA, len_A - len_B)
            else:
                curB = self.movePoint(curB, len_B - len_A)
    
            while curA is not None or curB is not None:
                if curA == curB:
                    return curA
                curA = curA.next
                curB = curB.next
    
            return None
  3. 总结:

    • 读题,leetcode输入和给出的函数样式并不完全一致,如本题,leetcode输入有skipA和skipB,但是给出的函数,却无法获取到skipA和skipB,因此读题要仔细,明确题目要求。

    • 此外,本题许多提示都在题目中,仔细阅读也会发现。

142. 环形链表 II

  1. 解析:https://programmercarl.com/0142.%E7%8E%AF%E5%BD%A2%E9%93%BE%E8%A1%A8II.html#%E6%80%9D%E8%B7%AF

  2. 题解:

    # Definition for singly-linked list.
    # class ListNode:
    #     def __init__(self, x):
    #         self.val = x
    #         self.next = None
    
    class Solution:
        def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
            """
            思路1:使用map,但是空间复杂度为O(N)
            思路2:双指针,当slow移动一步,fast移动两步,slow和fast一定会在环内相遇
            """
            if head is None:
                return None
            node_map = {}
            cur = head
            while cur is not None and cur not in node_map:
                node_map[cur] = 1
                cur = cur.next
            
            return cur
        
    class Solution:
        def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
            """
            思路:使用set,但是空间复杂度为O(N)
            """
            if head is None:
                return None
            visit = set()
            cur = head
            while cur is not None and cur not in visit:
                visit.add(cur)
                cur = cur.next
            return cur
  3. 总结:

    • 本题最容易想到的就是利用map,一旦发现指针已存入到map中,则找到环入口

    • 难以处理的是双指针,主要是数学推导、理解比较困难,其中最难的点还是fast一定会在环入口处追上slow不好理解。

    • 另外,这里使用set更加贴合实际,且相较于map多开辟一个空间存放没用的value,set则不存在这样的问题

    • 学习set的用法

day5---10.03

242. 有效的字母异位词

  1. 解析:

  2. 题解

    class Solution:
        def isAnagram(self, s: str, t: str) -> bool:
            if len(s) == 0 or len(t) == 0:
                return False
    
            countA = Counter(s)
            countB = Counter(t)
    
            if countA == countB:
                return True
            return False
  3. 总结:

    • 本题考哈希基础,统计每个字母出现的次数,若次数一样,则满足提议。

    • 这里重点学习一下Counter()

349. 两个数组的交集

  1. 解析:

  2. 题解:

     class Solution:
         def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
             """
             思路:
             1.Counter,记录每个数字出现次数,
             2.找出相同的数字
             3.返回最终结果
             """
             if len(nums1) == 0 or len(nums2) == 0:
                 return None
     ​
             count1 = Counter(nums1)
             count2 = Counter(nums2)
     ​
             res = []
             for num,_ in count1.items():
                 if num in count2:
                     res.append(num)
     ​
             return res
         
         
     class Solution:
         def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
             return list(set(nums1) & set(nums2))
  3. 总结:

    • 字典遍历、字典相关操作一定要清楚。如,遍历键值对:for key,value in dict.items();遍历键:for key in dict.keys();遍历值:for key in dict.values()

    • 字典元素删除,如:del count1[2]删除key=2的元素项;count1.clear():删除count1字典所有元素项;del count1:删除count1字典。

    • 字典内置函数:dict1 == dict2:比较两个字典的元素;len(dict):计算字典大小;

    • 其他如更新操作,这里暂不补充

    • 这里卡哥使用set,相较于counter,set更加节省空间,而且set还可以直接进行交集计算。

    • 关于set(),刷题时凡是涉及到无序、不重复元素等要求,首先要想到set。其次,本文中set集合使用了&运算符,这里的&运算符是集合的特权运算符,与之相比,还有如下集中运算符:|:求并集;&:求交集;-:差集;^:对称集;<=子集判断;>=:超集判断;<:真子集;>:真超集。因此,处理关系运算,set有天然的优势。

    • set()经典应用场景:去重问题、存在性检查、集合关系问题、

202. 快乐数

  1. 解析:

  2. 题解:

     class Solution:
         def isHappy(self, n: int) -> bool:
             """
             注意审题,无限循环,则false
             """
             rec = set()
             while True:
                 n = self.getSum(n)
                 if n == 1:
                     return True
                 if n in rec:
                     return False
                 else:
                     rec.add(n)
     ​
         def getSum(self, n: int) -> int:
             """计算n每一位的平方之和"""
             sum = 0
             while n != 0:
                 sum += (n % 10) * (n % 10)
                 n = n // 10
             return sum
  3. 总结:

    • 本题主要是从文中获取有关判定的提示,将数学问题转换为无限循环判定问题,从而引入set进行解决。

    • 本题主要难点,一个在于根据题目提示,转换为无线循环判定问题;另一个难点在于对数值各位进行求和,这里通过一次%10求个位,通过//10将原先十位将为个位,然后逐步求解。

    • 路漫漫其修远兮

1. 两数之和

  1. 解析:

  2. 题解:

     ​
     class Solution:
         def twoSum(self, nums: List[int], target: int) -> List[int]:
             """
             两数之和为target,采用map,key=num,value=index;每次遍历,确认map中是否有该值
             """
             rec = {}
             for i, num in enumerate(nums):
                 if target - num not in rec:
                     rec[num] = i
                 else:
                     return  [i, rec[target - num]]
             return None
  3. 总结:

    • 本题没什么好说的,做了第二遍了,主要问题还是在对于返回类型的把控上、字典的操作上,只能多多练习。

day6 --- 10.04

454. 四数相加 II

  1. 解析:https://programmercarl.com/0454.%E5%9B%9B%E6%95%B0%E7%9B%B8%E5%8A%A0II.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%88%E6%9C%AC

  2. 题解:

     class Solution:
         def fourSumCount(self, nums1: List[int], nums2: List[int], nums3: List[int], nums4: List[int]) -> int:
             """
             思路:
             1.四数相加转换为两数相加,与前面有题类似做一个哈希表,key= - (num1[i]+num2[j]), value = count,记录出现次数
             然后计算nums3[k] + nums4[l] 的值是否在value里面,是则count++
             """
             record_dict = defaultdict(int)
     ​
             for first in nums1:
                 for second in nums2:
                     record_dict[-(first + second)] += 1
     ​
             count = 0
             for first in nums3:
                 for second in nums4:
                     if (first + second) in record_dict.keys() and record_dict[(first + second)] > 0:
                         # count += 1
                         # record_dict[(first + second)] -= 1
                         count += record_dict[(first + second)]  # 此步是重点,没有AC的原因重点在这里
     ​
             return count
  3. 总结:

    • 本题做的时候思路基本无误,但是最后计算次数的时候存在问题,这里重点注意count += record_dict[(first + second)],因为对于当前的nums3+nums4而言,nums1+nums2record_dict[(first + second)种匹配模式,原先的写法只能匹配到一种组合方式。

    • 本题还需要重点学习record_dict = defaultdict(int)这种默认字典的命名方式,此外还可以用dict.get(key, 0)方式设置字典value初始值访问的返回值。

383. 赎金信

  1. 解析:https://programmercarl.com/0454.%E5%9B%9B%E6%95%B0%E7%9B%B8%E5%8A%A0II.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%88%E6%9C%AC

  2. 题解:

     class Solution:
         def canConstruct(self, ransomNote: str, magazine: str) -> bool:
             """
             思路:
             1.对两字符串分别建立字典,key=字符,value=出现次数,
             2.遍历ransomNote的字典,若key不在magazine中,或者value大于magazine的value则false
             """
             note_dict = defaultdict(int)
             magazine_dict = defaultdict(int)
     ​
             for ch in ransomNote:
                 note_dict[ch] = note_dict.get(ch, 0) + 1
     ​
             for ch in magazine:
                 magazine_dict[ch] = magazine_dict.get(ch, 0) + 1
     ​
             for key, value in note_dict.items():
                 if key not in magazine_dict or note_dict[key] > magazine_dict[key]:
                     return False
             return True
  3. 总结:

    • 比较简单

    • 此外,卡哥用数组做哈希,因为英文字符仅有26个,因此可以用index来作为每个字母的key,数组上存放的值则为其出现次数。相较于map,这样写更加的节省空间、时间。

15. 三数之和

  1. 解析:https://programmercarl.com/0015.%E4%B8%89%E6%95%B0%E4%B9%8B%E5%92%8C.html#%E6%80%9D%E8%B7%AF

  2. 题解

     class Solution:
         def threeSum(self, nums: List[int]) -> List[List[int]]:
             """
             思路:
             卡哥做排序,采用双指针
             :param nums:
             :return:
             """
             nums.sort()
             result = []
     ​
             for i in range(len(nums)):
                 left = i + 1
                 right = len(nums) - 1
     ​
                 if nums[i] > 0:
                     return result
     ​
                 if i > 0 and nums[i] == nums[i - 1]:  # a去重
                     continue
     ​
                 while left < right:
                     if (nums[i] + nums[left] + nums[right]) == 0:
                         result.append([nums[i], nums[left], nums[right]])
                         # left += 1 这里的left应该移动到下一个不同的值上面
                         while left < right and nums[left + 1] == nums[left]:
                             left += 1
                         while right > left and nums[right - 1] == nums[right]:
                             right -= 1
                         left += 1
                         right -= 1
                     elif (nums[i] + nums[left] + nums[right]) > 0:
                         right -= 1
                     else:
                         left += 1
     ​
             return result
  3. 总结:

    • 本题,a、b、c的去重需要考虑清楚,如果考虑不到位很容易出现重复结果

    • 做本题时,没想到将无序数组进行排序,从而简化编写难度。

    • 对于此类数组求和等运算类题目,首先因考虑是否可以将其先行进行排序,然后进行操作。

18. 四数之和

  1. 解析:https://programmercarl.com/0018.%E5%9B%9B%E6%95%B0%E4%B9%8B%E5%92%8C.html#%E6%80%9D%E8%B7%AF

  2. 题解:

     # 暴力。。。。超时套餐,
     # 卡哥用set没超时,我还没研究明白
     class Solution:
         def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
             """
             审题:(1)一个数组nums;(2)找出四个值,其和为target;(3)最终结果需要去重;(4)每组中的每个元素可以重复
             思路:索引和值未进行强绑定,先排序; 然后直接暴力哈希,使用set存储[nums[a], nums[b], nums[c], nums[d]]
             """
             nums.sort()
             result_set = set()
             for a in range(len(nums)):
                 if a <= len(nums) - 4:
                     b = a + 1
                     while b <= len(nums) - 3:
                         c = b + 1
                         while c <= len(nums) - 2:
                             d = c + 1
                             while d <= (len(nums) - 1) and (nums[a] + nums[b] + nums[c] + nums[d]) <= target:
                                 if nums[a] + nums[b] + nums[c] + nums[d] == target:
                                     result_set.add((nums[a], nums[b], nums[c], nums[d]))    # 列表不可哈希,元组可以
                                 d += 1
                             c += 1
                         b += 1
             result = []
             for res in result_set:
                 result.append(list(res))
     ​
             return result
        
     # 方法,四数之和问题转换未三数之和问题。。。。。
     class Solution:
         def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
             """
             审题:(1)一个数组nums;(2)找出四个值,其和为target;(3)最终结果需要去重;(4)每组中的每个元素可以重复
             思路:索引和值未进行强绑定,先排序; 然后转换为三数之和问题,[a, b, c, d]
             """
             nums.sort()
             size = len(nums)
             result = []
             for i in range(size):
                 if i > 0 and nums[i] == nums[i - 1]:    # a去重
                     continue
     ​
                 for j in range(i+1, size - 2):
                     if j > (i + 1) and nums[j] == nums[j - 1]:  # b去重
                         continue
                     left = j + 1
                     right = size - 1
                     while left < right:
                         gropu_sum = nums[i] + nums[j] + nums[left] + nums[right]
                         if gropu_sum > target:
                             right -= 1
                         elif gropu_sum == target:   # 记得bc也要去重
                             result.append([nums[i], nums[j], nums[left], nums[right]])
                             while left < right and nums[left] == nums[left + 1]:
                                 left += 1
                             while right > left and nums[right] == nums[right - 1]:
                                 right -= 1
                             left += 1
                             right -= 1
                         else:
                             left += 1
     ​
             return result
  3. 总结:

    • 从本题处理来看,三数之和还没有掌握。另外,对于这类问题,最重要的时去重,每一层的去重都要考虑到。

    • 处理此类问题的核心:排序、去重。排序我们用sort即可,对于去重,可以考虑的方式有哈希set、数组排序+双指针

    • 本题尚未掌握

day7---10.05

344. 反转字符串

  1. 解析:

  2. 题解:

     class Solution:
         def reverseString(self, s: List[str]) -> None:
             """
             Do not return anything, modify s in-place instead.
             思路:
             1.偷懒直接用python自带的库。。。。
             2.双指针
             3.新空间+逆序输出
             4.栈
             """
             if len(s) == 0:
                 return
             first = 0
             last = len(s) - 1
             while first < last:
                 temp = s[first]
                 s[first] = s[last]
                 s[last] = temp
                 first += 1
                 last -= 1
  3. 总结:

    • 这才是easy题!!!


动物装饰