【数据结构code】链表

203.移除链表元素

1、题目:

https://leetcode.cn/problems/remove-linked-list-elements/

2、描述:

在这里插入图片描述

3、重点:

虚拟头节点的使用技巧

4、分析


# 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]:
        # 创建虚拟头部节点以简化删除过程
        dummy_head = ListNode(next = head)
        
        # 遍历列表并删除值为val的节点
        current = dummy_head
        while current.next: # 最后一个节点的指针指向null,意味着已经遍历完了所有的节点
            if current.next.val == val:
                current.next = current.next.next
            else:
                current = current.next
        
        return dummy_head.next

707.设计链表

1、题目

https://leetcode.cn/problems/design-linked-list/

2、虚拟头节点的使用

重点:

  • 关注cur应该是dummy_head还是dummy_head.next
  • 关注遍历何时结束

代码实现:

class ListNode:
    def __init__(self,val=0,next=None):
        self.val = val
        self.next = next

class MyLinkedList(object):
    # 使用单链表方法
    def __init__(self):
        # 虚拟头节点
        self.dummy_head = ListNode()
        # 链表长度
        self.size = 0

    def get(self, index):
        """
        获取下表为index的节点的值
        :type index: int
        :rtype: int
        """
        # 首先判断index是否合法
        if index < 0 or index >= self.size:
            return -1

        # 定义临时指针
        cur = self.dummy_head.next # cur从头指针开始遍历
        for i in range(index):
            cur = cur.next

        return cur.val


    def addAtHead(self, val):
        """
        将一个值为 val 的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点
        :type val: int
        :rtype: None
        """
        ## 这里需要注意赋值顺序。
        # # 新建一个节点,next为head,即dummy.next
        # newnode = ListNode(val,next=self.dummy_head.next)
        # # 更改dummy.next
        # self.dummy_head.next = newnode

        # 也可以直接写为
        self.dummy_head.next = ListNode(val,self.dummy_head.next)
        self.size += 1


    def addAtTail(self, val):
        """
        将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
        :type val: int
        :rtype: None
        """
        # 新节点
        newnode = ListNode(val)
        # 临时指针
        cur = self.dummy_head
        # for i in range(size):
        #     cur = cur.next
        # 最后一个节点指向null,因此可以使用while
        while cur.next:
            cur = cur.next
        cur.next = newnode
        self.size += 1

    def addAtIndex(self, index, val):
        # 出错的地方!
        """
        将一个值为 val 的节点插入到链表中下标为 index 的节点之前。
        如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。
        如果 index 比长度更大,该节点将 不会插入 到链表中。
        :type index: int
        :type val: int
        :rtype: None
        """
        # 先判断index是否合法
        if index < 0 or index > self.size: # 这里为什么是大于,因为index可以为size,添加到尾部
            return
        # 临时指针
        cur = self.dummy_head
        for i in range(index):
            cur = cur.next
        
        cur.next = ListNode(val,cur.next)
        self.size += 1


    def deleteAtIndex(self, index):
        """
        如果下标有效,则删除链表中下标为 index 的节点
        :type index: int
        :rtype: None
        """
        # 先判断是否有效
        if index<0 or index >= self.size:
            return
        cur = self.dummy_head
        for i in range(index):
            cur = cur.next
        cur.next = cur.next.next
        # 注意增加或者删除时,size的变化
        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)

206.反转链表

1、题目链接:

https://leetcode.cn/problems/reverse-linked-list/

2、重点

如果再定义一个新的链表,实现链表元素的反转,其实这是对内存空间的浪费。

其实只需要改变链表的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表,如图所示:
在这里插入图片描述

3、分析

常考的题

共两种解法

  • 双指针法【先看懂这个】
  • 递归法【再理解这个】

循环内部定义了temp指针
这里要注意的是,赋值顺序

  1. 要先将cur赋值给pre
  2. 再将temp赋值给cur
# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
# 双指针法
class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        # 定义两个指针
        pre = None
        cur = head
        while cur:
            temp = cur.next
            cur.next = pre
            pre = cur
            cur = temp
        return pre

# 递归法
class Solution(object):
    def reverseList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        return self.reverse(head,None)
    def reverse(self,cur,pre):
        if cur == None:
            return pre
        temp = cur.next
        cur.next = pre
        return self.reverse(temp,cur)

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

1、链接:

https://leetcode.cn/problems/swap-nodes-in-pairs/

2、描述

在这里插入图片描述

3、重点分析

  • 链表长度为奇数,则最后一个点不进行交换
  • 若为偶数,正好可以两两交换

交换时,链表头节点发生了变化,所以需要dummy_head

4、代码

方法一:
在交换前,需要保存一下1和3!!!

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
# 方法一 | 虚拟头节点
class Solution(object):
    def swapPairs(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        dummyhead = ListNode(next=head) # 头节点
        cur = dummyhead
        while (cur.next!=None) and (cur.next.next!=None):
        # 这个while也可以写为:
        # while cur.next and cur.next.next:
            # 注意结束条件,考虑奇数和偶数情况,注意先后顺序
            temp = cur.next # 1
            temp1 = cur.next.next.next # 3
            cur.next = cur.next.next # cur->2
            cur.next.next = temp # 2->1
            cur.next.next.next = temp1 # 1->3 # 注意这里!不要犹豫
            cur = cur.next.next # cur移动2
        return dummyhead.next

方法二:递归,这里看的不是很懂

# 方法二 | 递归 不需要虚拟头节点
class Solution(object):

    def swapPairs(self, head):
        """
        两个指针进行两两交换
        :type head: ListNode
        :rtype: ListNode
        """
        if head is None or head.next is None: # 终止条件:链表没有节点,或者链表中只有一个节点
            return head
        # 待翻转的两个节点
        pre = head
        cur = head.next
        next1 = head.next.next
        # 交换
        cur.next = pre # 第二个指向第一个
        # 交换后,原链表的头节点变成新链表第二个节点,原链表的第二个节点变成新链表的头节点
        pre.next = self.swapPairs(next1)# 将以next为head的后续链表两两交换

        return cur

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

1、链接:

https://leetcode.cn/problems/remove-nth-node-from-end-of-list/

2、描述

在这里插入图片描述

3、重点分析

既然是倒数第n个点,可以使用双指针
快指针先走n+1步,然后快慢指针同时走。
当快指针走到null时,慢指针的next便是需要删除的

  • 删除节点需要前驱
  • 倒数第n个节点可能是头节点,需要dummy_head

4、代码

class Solution(object):
    def removeNthFromEnd(self, head, n):
        """
        :type head: ListNode
        :type n: int
        :rtype: ListNode
        """
        # 需要设置虚拟头节点,考虑要删除的点是头节点的情况 | 第一个错误点,没有考虑到头节点
        dummyhead = ListNode(next=head)
        fast,slow = dummyhead,dummyhead# 定义快慢指针
        n += 1
        for i in range(n): # 第二个错误点,fast移动n个点,用for循环,不是while
            fast = fast.next
        # while (n > 0) and fast:
        #     fast = fast.next # 快指针先走n+1步
        #     n -= 1
        while fast:# 快慢指针一起走,直到fast指向none
            fast = fast.next
            slow = slow.next
        slow.next = slow.next.next
        return dummyhead.next

面试题 02.07. 链表相交

1、链接:

简单题~
https://leetcode.cn/problems/intersection-of-two-linked-lists-lcci/

2、描述

在这里插入图片描述

3、重点分析

4、代码

class Solution(object):
    def getIntersectionNode(self, headA, headB):
        """
        :type head1, head1: ListNode
        :rtype: ListNode
        """
        # 先求两个链表的长度
        n = 0
        m = 0
        curA = headA
        curB = headB
        while curA:
            curA = curA.next
            n += 1
        while curB:
            curB = curB.next
            m += 1
        if m > n:
            fast = headB
            slow = headA
        else:
            fast = headA
            slow = headB
        for i in range(abs((m-n))):
            fast = fast.next
        while fast != slow:
            fast = fast.next
            slow = slow.next
        return fast

142.环形链表II

1、链接:

https://leetcode.cn/problems/linked-list-cycle-ii/

2、描述

1、找到是否有环
2、去找环形的入口
在这里插入图片描述

3、重点分析

在这里插入图片描述

4、代码

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

class Solution(object):
    def detectCycle(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        # 先判断有没有环
        fast , slow = head , head
        while (fast != None) and (fast.next != None):
        # 可以写成:while fast and fast.next:
            fast = fast.next.next # 移动两步
            slow = slow.next # 移动一步
            if fast == slow:
                # 相遇 有环  -》寻找环的入口
                index1 = head
                index2 = fast
                while index1 != index2:
                    index1 = index1.next
                    index2 = index2.next
                return index1
        # 没有环
        return None
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值