leetcode 中的链表简单题 python3

目录:

基本使用 //

21题 合并有序链表 //

83题 删除有序链表重复元素 //

141题 环形链表 //

160题 相交链表 //

203题 移除链表元素//

206题 反转链表 //

基本使用:

之前没有学过链表,leetcode最近在做简单题,才发现链表的定义,元素之间是通过节点连接的。链表类定义以后的函数调用解释:

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next

p = ListNode()
l1: ListNode 
#l1 就是链表里的指针所在的位置以及之后的元素

#若此链表为[1, 2, 3] 
#l1 = [1, 2, 3]
#l1.next = [2, 3]
l1.val #默认第0个元素 例子中为1

l1 = l1.next #指针后移
#此时l1.val 为2
#l1.next = [3]


p.next = ListNode(l1.val) #这个元素值赋给链表p的下一个元素

21题 合并有序链表

将两个有序链表合并为一个新的升序链表

class Solution:
    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        p = ListNode()
        ans = p
        while l1 and l2:
            if l1.val < l2.val:
                p.next = ListNode(l1.val)
                l1 = l1.next
            else:
                p.next = ListNode(l2.val)
                l2 = l2.next
            p = p.next
        if l1:
            p.next = l1
        else:
            p.next = l2
        return ans.next
# p.next不被直接返回是因为p此时指针已经到了最后一个元素
#而提前设置的ans和p指向同一个链表,那么使用ans.next返回整个链表

83题 删除排序链表中的重复元素

1. 设置prev, cur = head, head.next, prev与head指向同一个链表 ;

2. perv.val == cur.val 时 prev跳过下一个值(cur.val) 直接保存next为cur.next 即 prev.next = cur.next ;  (指到后继节点的后继节点来删除本身的后继节点)

3. 若非如此,prev后移一个即 prev = cur. ;

4. 无论如何,cur = cur.next 后移往前进着

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def deleteDuplicates(self, head: ListNode) -> ListNode:
        if not head:
            return head
        perv, cur = head, head.next
        while cur:
            if perv.val == cur.val:
                perv.next = cur.next
            else:
                perv = cur
            cur = cur.next
        return head

141题 环形链表

看了某站up的讲解,才知道环形链表的意思...

环形通常出现在有循环处,那么一般就可用这两种常见办法。同类题型可见202题 快乐数。

方法一: 又顺便学了哈希表,哈希表在python里就是dict和set. dict相当于保存2个list,一个元素本身 一个下标(映射)。set保存1个list,元素本身。这个题可以使用哈希表存储,环形链表的环会存在于已建立的哈希表内,因此True条件为:node in s

class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        if not head: return False
        s = set()
        node = head
        while node:
            if node in s:
                return True
            else:
                s.add(node)
            node = node.next
        return False

方法二:快慢指针。还是很好理解的

class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        if not head: return False
        fast = slow = head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next 
            #总是快一步,那么进入循环后总会在第二圈赶上slow,即相等
            if slow == fast:
                return True
        return False

160题 相交链表

方法一:用哈希表存储headA的所有后续节点,遍历headB,若遍历到指针存在于此哈希表,则说明存在。(这个是自己想出来的~)

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        s = set()
        nodeA = headA
        nodeB = headB
        while nodeA:
            s.add(nodeA)
            nodeA = nodeA.next
        while nodeB:
            if nodeB in s:
                return nodeB
            nodeB = nodeB.next
        return None

方法二:双指针。(来源用户 Krahets 题解)假设headA有a个节点,headB有b个节点,相交于c节点,设置2个指针:指针A从headA开始遍历,结束后遍历B至节点处需要走 (a+b-c) 个节点;指针B从headB开始遍历,结束后遍历A至节点处需要走 (b+a-c) 个节点,指针会相遇。返回此时指针A,若不相遇则A会遍历完 a+b 所有节点指向null. 时间复杂度O(a+b), 空间复杂度O(1) 常数大小的额外空间。

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        A, B = headA, headB
        while A != B:
            A = A.next if A else headB 
            #若headA遍历完成则A=headB开始遍历
            B = B.next if B else headA
        return A

看到评论有人问为什么 A = A.next if A else A = headB 会报错,因为A = 赋值+赋值条件,后面是一个模块,等于语句 if A: A = A.next else: A = headB.  ifelse语句在赋值使用当然不需要再加赋值号啦...

203题 移除链表元素

思路很简单,保证第一个节点满足要求,然后进入判断循环,如果后继节点等于val就跳过后继节点赋值给next,否则直接指针后移。注意一点在保证头节点满足要求之后💊增加None判断否则不能使用.next attribute会一直报错。

class Solution:
    def removeElements(self, head: ListNode, val: int) -> ListNode:
        while head and head.val == val:
            head = head.next
        if not head: return head
        node = head
        while node.next:
            if node.next.val == val:
                node.next = node.next.next
            else:
                node = node.next
        return head       

206题 反转链表

这个很难理解啊。迭代+递归。

方法一:迭代。(双指针)

设置双指针pre和cur. pre指向none,cur指向head. 再增加一个保存变量temp来储存cur.next

1. 保存cur.next.

2. 将cur.next指向pre  此时cur只有第一个元素,指向pre

3. 将cur赋给pre  pre就成为head前面的元素

4. 下次迭代:cur=temp找回剩余链表,cur.next指向pre(即现有元素指向前面的元素2-1/3-(2-1),就实现了反转)。

比如链表:1-2-3.

先保存2-3为temp, cur.next = pre = None, cur为1. pre = cur = 1, cur = temp = 2-3 ;

2次迭代:temp保存3, cur.next = pre = 1, 相当于让2指向1,这就实现了反转。pre = cur = 2-1. cur = temp = 3.

3次迭代:temp = None. cur = 3,  cur.next = pre = 2-1. pre = cur = 3-2-1. cur = temp = None 退出循环。

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        pre, cur = None, head
        while cur:
            temp = cur.next
            cur.next = pre #下一个元素指向本元素的过程
            pre = cur
            cur = temp
        return pre

方法二:递归

核心思想是:已经反转了后面元素,只需要将第二个元素指向第一个。

这里实现反转的过程是:1 head.next.next = head; 2 head.next = None

将下个元素的下个元素指向本元素,再切段本元素与下个元素的线。

比如:原链表1-2-3-4-5,现已反转完后面所有1->2<-3<-4<-5,第1步 head.next = 2, 即是让2指向1: 2->1 ;第2步 切断1->2这条线!

class Solution:
    def reverseList(self, head: ListNode) -> ListNode:
        if not head or not head.next: return head
        cur = self.reverseList(head.next) #永远代表着反转后的链表
        head.next.next = head
        head.next = None
        return cur

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值