笔记——week12

week12


知识点记录:

pop():

在Python中,pop()是列表(List)的一个方法,用于移除列表中的元素,并返回被移除的元素值。pop()方法可以接受一个可选的参数,用于指定要移除的元素的索引位置,默认为最后一个元素。

例如,对于列表nums = [1, 2, 3, 4, 5]

  1. nums.pop()将移除并返回最后一个元素5,列表变为[1, 2, 3, 4]

  2. nums.pop(1)将移除并返回索引位置为1的元素2,列表变为[1, 3, 4, 5]

注意:如果使用pop()方法时不指定索引位置,并且列表为空,将会引发IndexError异常。因此,在使用pop()方法之前,最好先检查列表是否为空。

简单类型:

160. 相交链表

题目描述:

给你两个单链表的头节点 headAheadB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null

图示两个链表在节点 c1 开始相交**:**

img

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构

自定义评测:

评测系统 的输入如下(你设计的程序 不适用 此输入):

  • intersectVal - 相交的起始节点的值。如果不存在相交节点,这一值为 0
  • listA - 第一个链表
  • listB - 第二个链表
  • skipA - 在 listA 中(从头节点开始)跳到交叉节点的节点数
  • skipB - 在 listB 中(从头节点开始)跳到交叉节点的节点数

评测系统将根据这些输入创建链式数据结构,并将两个头节点 headAheadB 传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案

示例 1:

img

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
输出:Intersected at '8'
解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,6,1,8,4,5]。
在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
— 请注意相交节点的值不为 1,因为在链表 A 和链表 B 之中值为 1 的节点 (A 中第二个节点和 B 中第三个节点) 是不同的节点。换句话说,它们在内存中指向两个不同的位置,而链表 A 和链表 B 中值为 8 的节点 (A 中第三个节点,B 中第四个节点) 在内存中指向相同的位置。
code_1:
class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
        def get_length(head):  #  链表长度的获取
            length = 0
            while head:
                length += 1
                head = head.next
            return length

        lenA, lenB = get_length(headA), get_length(headB)
        p1, p2 = headA, headB

        # 调整链表的起始位置,使得它们从同样长度开始
        while lenA > lenB:
            p1 = p1.next
            lenA -= 1
        while lenB > lenA:
            p2 = p2.next
            lenB -= 1

        # 同时移动指针p1和p2,直到它们相遇或者都指向null
        while p1 and p2:
            if p1 == p2:
                return p1
            p1 = p1.next
            p2 = p2.next

        return None
解题思路:

双指针,这次判断的条件是第一个地址相同的地方,也就是两个指针相遇。思路还是比较简单的

  1. 使指针的首地址相同
  2. 让指针相遇
  3. 否则:None
code_2:
class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
        if not headA or not headB:
            return None  # 如果其中一个链表为空,直接返回None,因为不可能相交
        
        pA, pB = headA, headB  # 初始化两个指针分别指向两个链表的头节点
        while pA != pB:
            pA = pA.next if pA else headB  # 如果pA指针到达链表末尾,则重新从headB开始遍历
            pB = pB.next if pB else headA  # 如果pB指针到达链表末尾,则重新从headA开始遍历
        
        return pA  # 返回相交的起始节点,若没有相交,则pA会在遍历完两个链表后都为None

解题思路:

这个也是双指针算法,根据官方题解写的,时间开销和空间开销是差不多的。提供学习

206. 反转链表

题目描述:

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

img

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]
code:
# 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]:
        p = None  # 用于记录当前已经反转的链表的头节点,初始值为None
        current_node = head  # 遍历指针,初始值为链表的头节点

        while current_node:
            next_node = current_node.next  # 记录当前节点的下一个节点,以便后续迭代
            current_node.next = p  # 当前节点的next指针指向已经反转的链表
            p = current_node  # 更新p为当前节点,表示已经反转的链表的头节点
            current_node = next_node  # 更新遍历指针为下一个节点,继续迭代
        
        return p  # 返回p作为反转后的链表的头节点

解题思路:

使用迭代的方法进行链表反转。定义一个新的变量p来记录当前已经反转的链表,初始值为None。然后,遍历原链表,每次迭代都将当前节点的next指针指向前一个节点,实现链表的反转。在遍历的过程中,需要保存当前节点的下一个节点next_node,以防止丢失后续节点。最后,p节点将指向新的头节点,返回p作为反转后的链表头节点就是结果。

中等类型:

238. 除自身以外数组的乘积

题目描述

给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积

题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。

请**不要使用除法,**且在 O(*n*) 时间复杂度内完成此题。

示例 1:

输入: nums = [1,2,3,4]
输出: [24,12,8,6]
code:
class Solution:
    def productExceptSelf(self, nums: List[int]) -> List[int]:
        length = len(nums)  # 长度的获取
        answer = [0]*length  # 结果数组
        answer[0] = 1  # 设置为一不改变大小
        for i in range(1, length):  # 每个元素左边的累积
            answer[i] = nums[i - 1] * answer[i - 1]
        R = 1;  # 记录元素右边的累积
        for i in reversed(range(length)):  # 从右向左扫描
            answer[i] = answer[i] * R
            R *= nums[i]
        
        return answer
解题思路:

请**不要使用除法,**且在 O(*n*) 时间复杂度内完成此题。有要求限制,而且考虑到0的存在也无法使用除号。

先记录每个元素左边的累积,在从右向左扫描,乘以元素右边的累积。

78. 子集

题目描述:

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:

输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
code:
class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        n = len(nums)  # 数组的长度
        res = [[]]  # 初始化结果列表,空集也是子集

        def backtrack(curr, choices):
            if not choices:  # 当前选择列表为空,即没有更多元素可选,返回
                return

            for i in range(len(choices)):  # 遍历每个元素
                num = choices[i]  # 选择的数字
                res.append(curr + [num])  # 将当前选择加入结果列表中
                backtrack(curr + [num], choices[i+1:])  # 继续递归,将当前选择后面的元素作为新的选择列表

        backtrack([], nums)  # 调用递归函数开始生成子集
        return res  # 返回结果列表
解题思路:

46. 全排列的思路差不多,回溯算法,不同的是,该题需要的是不重复的所有节点,所以在记录节点的方式上有所不同。

47. 全排列 II

题目描述:

给定一个可包含重复数字的序列 nums按任意顺序 返回所有不重复的全排列。

示例 1:

输入:nums = [1,1,2]
输出:
[[1,1,2],
 [1,2,1],
 [2,1,1]]
code:
class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        # 先排序保证相同的数字相邻
        nums.sort()
        # 结果
        res = []
        # 长度
        n = len(nums)
        def backtrack(curr, choices):
            """
            回溯函数

            Args:
                curr: 当前排列
                choices: 剩余的数字

            Returns:
                无
            """
            # 如果没有数字了,就添加到结果中
            if not choices:
                res.append(curr)
                return

            # 遍历所有的数字
            for i in range(len(choices)):
                # 如果当前数字已经被使用过了,就跳过
                if i > 0 and choices[i] == choices[i-1]:
                    continue

                # 选择当前数字
                num = choices[i]

                # 递归地调用函数,选择剩余的数字
                backtrack(curr + [num], choices[:i] + choices[i+1:])

        # 从空数组开始
        backtrack([], nums)

        return res

解题思路:

46. 全排列的思路差不多,回溯算法,不同的是,该题需要的是所有不重复的全排列,所以先是基础的回溯算法,根据题目经行剪枝,判断条件是如果当前数字是否使用过

209. 长度最小的子数组

题目描述:

给定一个含有 n 个正整数的数组和一个正整数 target

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度**。**如果不存在符合条件的子数组,返回 0

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
code:
class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        n = len(nums)  # 获取数组的长度
        ans = n + 1  # 取一个最大值作为比较的初始值
        l = 0  # 为左指针初始化
        s = 0  # 窗口的和
        for r, x in enumerate(nums):  # 开始移动右指针x=nums[r] 
            s += x
            while s - nums[l] >= target:  # 左指针移动
                s -= nums[l]
                l += 1
            if s >= target:
                ans = min(ans, r - l + 1)
        return ans if ans <= n else 0  # 注意可能数组的值不会大于target
解题思路:

比较简单的窗口移动,利用题目数组都是整数的特点经行左指针的移动。

713. 乘积小于 K 的子数组

题目描述:

给你一个整数数组 nums 和一个整数 k ,请你返回子数组内所有元素的乘积严格小于 k 的连续子数组的数目。

示例 1:

输入:nums = [10,5,2,6], k = 100
输出:8
解释:8 个乘积小于 100 的子数组分别为:[10]、[5]、[2],、[6]、[10,5]、[5,2]、[2,6]、[5,2,6]。
需要注意的是 [10,5,2] 并不是乘积小于 100 的子数组。
code:
class Solution:
    def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int:
        if k <= 1:  # 考虑到数组的数都是正整数
            return 0
        ans = 0  # 记录结果
        p = 1  # 统计窗口乘积
        l = 0  # 左端点
        for r, x in enumerate(nums):  # 右指针遍历
            p *= x  # 先乘上右指针的数
            while p >= k:  # 移动左指针
                p /= nums[l]
                l += 1
            ans += r - l + 1
        return ans
解题思路:

解法和209. 长度最小的子数组还是相同的不同的是ans的计算,这里使用的是ans += r - l + 1

if p[l, r] < k:  # p数组内所有元素的乘积
	p[l+1, r], p[l+2, r]... < k  # 所以ans += r - l + 1

找到右指针不变满足条件最长的字串。

其他:


本周写的leetcode比较少,开始写C++的题和看算法书,下周就是每天最少三道python的,要加快进度。大部分都有思路并且可以自己在30min以内独立完成(在学的部分),剩下的就是如何优化,写题解。会一点还是比什么都不会要好写一点,也带着看些视频,书籍,和一些巨佬的博客。

部分题开始使用Google的聊天机器人Bard经行代码的注释添加(我写的比较简单),优化算法以及算法解释(比我写的详细),我也在向它的标准化学习。个人感觉他比openaichatgpt要好用一点(当然可能是因为我没为它升级)


l + 1`

if p[l, r] < k:  # p数组内所有元素的乘积
	p[l+1, r], p[l+2, r]... < k  # 所以ans += r - l + 1

找到右指针不变满足条件最长的字串。

其他:


本周写的leetcode比较少,开始写C++的题和看算法书,下周就是每天最少三道python的,要加快进度。大部分都有思路并且可以自己在30min以内独立完成(在学的部分),剩下的就是如何优化,写题解。会一点还是比什么都不会要好写一点,也带着看些视频,书籍,和一些巨佬的博客。

部分题开始使用Google的聊天机器人Bard经行代码的注释添加(我写的比较简单),优化算法以及算法解释(比我写的详细),我也在向它的标准化学习。个人感觉他比openaichatgpt要好用一点(当然可能是因为我没为它升级)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值