zoukankan      html  css  js  c++  java
  • LeetCode:链表(一)

    本组囊括链表相关题目,难度不等。

    2. Add Two Numbers

    题目描述:中等

    思路一:

    主要难点是进位的问题,使用取模和整除来求解,具体看代码中的注释:

     1 # Definition for singly-linked list.
     2 # class ListNode:
     3 #     def __init__(self, x):
     4 #         self.val = x
     5 #         self.next = None
     6 
     7 class Solution:
     8     def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
     9 
    10         # 链表, 用取模和整除来解
    11         dummy = ListNode(0) # 预备哑节点/虚拟节点,但它不存储数字,初始化它和current相同。
    12         current = dummy 
    13         carry = 0   # 初始化进位
    14         while l1 or l2:  
    15             x = l1.val if l1 else 0 # 设置x为l1头节点的值,也就是个位数,如果l1节点已经到达了null,设置x为0 
    16             y = l2.val if l2 else 0 # 同上
    17             sum = x + y + carry 
    18             carry = sum // 10  # 求进位是否为1
    19             current.next = ListNode(sum%10)  # 创建一个值为sum mod 10的节点,并将current的next指向它
    20             if l1:  # 防止下位为空,不为空则向前移动l1,l2的节点
    21                 l1 = l1.next
    22             if l2:
    23                 l2 = l2.next
    24             current = current.next # 同时 current的指向变为当前的新节点。
    25             if carry != 0: # 判断carry是否等于1,如果等于1,在链表末尾增加一个为1的节点,这里只是个形式(防止后面没有数字了,直接进1,如果有数字会继续执行覆盖这个1),后面的sum会加一个carry为1.
    26                 current.next = ListNode(1)
    27         return dummy.next # 返回dummy的next,也就是个位数开始的地方
    28         # 初始化的节点dummy没有存储值,最后返回dummy的next 。这样的好处是不用单独对head进行判断改变值。也就是如果一开始的 head 就是代表个位数,那么开始初始化的时候并不知道它的值是多少,所以还需要在进入循环前单独对它进行值的更正,不能像现在一样只用一个循环简洁。
    29 
    30         # 时间复杂度:O(max(m,n)),假设 m 和 n 分别表示 l1 和 l2 的长度,上面的算法最多重复max(m,n) 次。
    31         # 空间复杂度:O(max(m,n)),新列表的长度最多为max(m,n)+1。

     

    19. Remove Nth Node From End of List

    题目描述:中等

    思路一:

    先计算链表长度的方法当然可行,但需要两次遍历链表;我们来考虑一下进阶所说的如何通过一遍扫描实现;

    考虑使用两个指针,快慢指针都指向头节点;

    (1)让快指针先前进n步,如果前进n步后head已经到达空节点,则证明原链表长度为n,删除倒数第n个节点即为删除第一个节点;

    (2)如果前进n步快指针未到达空节点,则让慢指针与快指针同步前进,直到慢指针.next为空,这样的话慢指针就到达了要删除节点的前一节点处,再更改next指向即可。

     1 class Solution:
     2     def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
     3         # 删除倒数第n个节点,即索引为len-n
     4         # 考虑两个特殊位置,删除开头和结尾
     5         # 考虑不用计算链表长度的方法
     6         if not head:
     7             return 0
     8         dummy = ListNode(0) # 同样先设置一个哑节点,虚拟节点,val为None,指向第一个节点。方便最后返回本身的链表头结点
     9         headc = head 
    10         dummy.next = head 
    11         for i in range(n): # 让head先前进n步
    12             head = head.next 
    13         if not head:# 如果前进n步后head已经到达空节点,则证明原链表长度为n,删除倒数第n个节点即为删除第一个节点
    14             headc = headc.next # 这样即是删除第一个节点
    15             return headc 
    16         # 如果前进n步head未到达空节点,则让head与headc同步前进,直到head.next为空
    17         while head.next != None:
    18             head = head.next
    19             headc = headc.next
    20         # 设链表长度为n,则这样的话headc就走了len-1-n步到达要删除节点的前一节点
    21         headc.next = headc.next.next  # 此时使前一节点指向被删除节点所指向的下一节点
    22         return dummy.next
    23         # 时间复杂度:O(N),该算法对含有N个结点的列表进行了一次遍历。因此时间复杂度为O(N)。
    24         # 空间复杂度:O(1),我们只用了常量级的额外空间。

    21. Merge Two Sorted Lists

    题目描述:简单

    思路一:迭代解法

    像极了合并两个有序数组。
    遍历两个链表,每次返回值较低的节点;具体看代码注释:

     1 # Definition for singly-linked list.
     2 # class ListNode:
     3 #     def __init__(self, val=0, next=None):
     4 #         self.val = val
     5 #         self.next = next
     6 class Solution:
     7     def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
     8         # 解法一:迭代解法
     9         # 像极了合并两个有序数组。
    10         # 遍历两个链表,每次返回值较低的节点
    11         head = ListNode(0)  # 固定格式,一个头节点用于生成新链表
    12         dummy = head        # 一个虚拟节点用于最后返回整个生成的链表
    13         while l1 and l2:
    14             if l1.val < l2.val:
    15                 head.next = l1 # 记住,next指向的是下一个节点而不是下一个节点的值!否则不会形成链表
    16                 head = head.next # 每次更新head指向
    17                 l1 = l1.next
    18             else:
    19                 head.next = l2
    20                 head = head.next
    21                 l2 = l2.next
    22         # 如果前面循环没有进行,则l1/l2其中一个为空链表,则直接返回另一个链表
    23         # 如果前面循环进行了,在循环终止的时候, l1 和 l2 至多有一个是非空的。由于输入的两个链表都是有序的,所以不管哪个链表是非空的,它包含的所有元素都比前面已经合并链表中的所有元素都要大。这意味着我们只需要简单地将非空链表接在合并链表的后面,并返回合并链表即可。
    24         if not l1:
    25             head.next = l2
    26         if not l2:
    27             head.next = l1  
    28         return dummy.next
    29         # 时间复杂度:O(N+M),M和N分别为两个链表的长度;
    30         # 空间复杂度O(1)

    思路二:递归

    暂时留坑

  • 相关阅读:
    在VMWare虚拟机下的ubuntu中Samba服务的安装
    Shell表达式,如${file##*/}
    如何从官网下载QT
    SATA命令之security
    Clip
    JS判断是否在微信浏览器打开
    微信小程序请求数据报错: 如若已在管理后台更新域名配置,请刷新项目配置后重新编译项目,操作路径:“详情-域名信息”
    typeof()和instanceof的用法区别
    javascrip 对数组的操作方法
    微信小程序 修改数据,并动态渲染页面;修改数组;
  • 原文地址:https://www.cnblogs.com/Jesee/p/13952477.html
Copyright © 2011-2022 走看看