Leetcode题解-算法-链表(python版)

本文详细介绍了多种链表操作的算法实现,包括找到两个链表的交点、链表的反转、合并两个有序链表、从有序链表中删除重复节点、删除链表中倒数第n个节点、交换链表中相邻节点、计算两链表之和、判断回文链表、分隔链表以及按奇偶分组链表。这些算法涵盖了链表操作的基础和进阶技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、找出两个链表的交点

160. 相交链表(Easy)

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

class Solution(object):
    def getIntersectionNode(self, headA, headB):
        p1, p2 = headA, headB
        while p1 != p2:
            p1 = headB if p1 == None else p1.next
            p2 = headA if p2 == None else p2.next
        return p1

2、链表反转

206. 反转链表(Easy)

# 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):
        pre = None
        cur = head
        while cur != None:
            nextp = cur.next
            cur.next = pre
            pre = cur
            cur = nextp
        return pre

3、归并两个有序链表

21. 合并两个有序链表(Easy)

方法一:迭代
每次找两个链表中较小的值加入新的链表,直到有一个链表遍历结束,未结束的那个链表,将剩余的部分连到新链表的尾部。

# 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 mergeTwoLists(self, l1, l2):
        if not l1:
            return l2
        if not l2:
            return l1
        p1, p2 = l1, l2
        head = tail = ListNode(0)
        while p1 and p2:
            if p1.val < p2.val:
                tail.next = p1
                p1 = p1.next
            else:
                tail.next = p2
                p2 = p2.next
            tail = tail.next
        if p1:
            tail.next = p1
        if p2:
            tail.next = p2
        return head.next

方法二:递归

# 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 mergeTwoLists(self, l1, l2):
        if not l1: return l2
        if not l2: return l1
        if l1.val < l2.val:
            l1.next = self.mergeTwoLists(l1.next, l2)
            return l1
        else:
            l2.next = self.mergeTwoLists(l1, l2.next)
            return l2

4、从有序链表中删除重复结点

83. 删除排序链表中的重复元素(Easy)

方法:一次遍历
思路1:重复元素为一组,每组重复元素中只取第一个元素,cur 为当前组第一个,找下一组的第一个元素nex,另cur.next = nex

# 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 deleteDuplicates(self, head):
        if not head or not head.next:
            return head
        cur, nex = head, head.next
        while cur:
            while nex and cur.val == nex.val:
                nex = nex.next
            cur.next = nex
            cur = nex
        return head

思路2:每次只看下一个节点,如果当前 cur 与 cur.next 对应的元素相同,那么就将 cur.next 从链表中移除;否则说明链表中已经不存在其它与 cur 元素相同的节点,将 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 deleteDuplicates(self, head):
        if not head or not head.next:
            return head
        cur = head
        while cur.next:
            if cur.val == cur.next.val:
                cur.next = cur.next.next
            else:
                cur = cur.next
        return head

5、删除链表中倒数第 n 个结点

19. 删除链表的倒数第 N 个结点(Medium)
问题分析:
两个指针 fast,slow,先让 fast 走 n 步,让后二者一起走,直到 fast->next==NULL,此时 slow 指向倒数第 n+1个结点。
注意:如果 fast 先走 n 步后,发现 fast->next==NULL,表示删除头节点。

# 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 removeNthFromEnd(self, head, n):
        slow, fast = head, head
        for _ in range(n):
            fast = fast.next
        if not fast:		# 删除的是第一个节点
            return head.next
        while fast.next:
            fast = fast.next
            slow = slow.next
        slow.next = slow.next.next
        return head

6、交换链表中相邻的结点

24. 两两交换链表中的节点(Medium)
方法一:递归
如果链表为空或者只有一个节点,直接返回
否则递归,递归过程如下:
在这里插入图片描述

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

class Solution(object):
    def swapPairs(self, head):
        if head == None or head.next == None:
            return head
        node = head.next
        head.next = self.swapPairs(node.next)
        node.next = head
        return node

时间复杂度:O(N),N 指的是链表的节点数量。
空间复杂度:O(N),递归过程使用的堆栈空间。

方法二:迭代

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

class Solution(object):
    def swapPairs(self, head):
        front = ListNode(-1)
        pre_node = front
        pre_node.next = head
        while head and head.next:
            first_node = head
            second_node = head.next
            # 交换两个节点
            pre_node.next = second_node
            first_node.next = second_node.next
            second_node.next = first_node
            # 改变head和pre_node指向,为下一轮交换做准备
            head = first_node.next
            pre_node = first_node
        return front.next

时间复杂度:O(N),N 为链表的节点数量
空间复杂度:O(1)

7、两链表的和

445. 两数相加 II(Medium)

方法1:翻转两链表,这样保证链表右端对齐,再相加。注意:这里相加之和大于 10 需要向该节点的前一结点进位。

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next =  
class Solution(object):
    def addTwoNumbers(self, l1, l2):
        def reverse_list(head):
            pre = None
            cur = head
            while cur:
                nex = cur.next
                cur.next = pre
                pre = cur
                cur = nex
            return pre

        l1 = reverse_list(l1)
        l2 = reverse_list(l2)
        cur_val = 0
        newhead = ListNode(-1)
        tail = newhead
        while l1 and l2:
            cur_val += l1.val + l2.val
            l1 = l1.next
            l2 = l2.next
            p = ListNode(cur_val % 10)
            tail.next = p
            tail = p
            cur_val = cur_val / 10
        while l1:
            cur_val += l1.val
            l1 = l1.next
            p = ListNode(cur_val % 10)
            tail.next = p
            tail = p
            cur_val = cur_val / 10
        while l2:
            cur_val += l2.val
            l2 = l2.next
            p = ListNode(cur_val % 10)
            tail.next = p
            tail = p
            cur_val = cur_val / 10
        while cur_val:
            p = ListNode(cur_val % 10)
            tail.next = p
            tail = p
            cur_val = cur_val / 10
        p.next = None
        return reverse_list(newhead.next)

方法2:使用栈,把所有数字压入栈中,再依次取出相加。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
        s1, s2 = [], []
        while l1:
            s1.append(l1.val)
            l1 = l1.next
        while l2:
            s2.append(l2.val)
            l2 = l2.next
        carry = 0
        ans = None
        while s1 or s2 or carry:
            val1 = s1.pop() if s1 else 0
            val2 = s2.pop() if s2 else 0
            sum = val1 + val2 + carry
            curnode = ListNode(sum%10)
            carry = sum//10
            curnode.next = ans
            ans = curnode
        return ans 

8、回文链表

234. 回文链表(Easy)

问题分析:
将链表的前一半反转,判断前一半与后一半是否相等,如:
1 -> 2 -> 2 -> 1 -> NULL 拆分为 NULL <- 1 <- 2 与 2 -> 1 -> NULL
1 -> 2 -> 1 -> NULL 拆分为 NULL <- 1 与 1 -> NULL

# 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 isPalindrome(self, head):
        len = 0
        p = head
        while p:
            len += 1
            p = p.next
        odd = len % 2
        pre = None
        cur = head
        for _ in range(len//2): #前一半反转
            nex = cur.next
            cur.next = pre
            pre = cur
            cur = nex
        p1, p2 = pre, cur
        if odd:                 #如果链表个数为奇数,中间一个数不比较
            p2 = p2.next
        while p1:
            if p1.val != p2.val:
                return False
            p1 = p1.next
            p2 = p2.next
        return True

9、分隔链表

725. 分隔链表(Medium)

解题思路:根据总长度和分成多少段,可以求出短链表的长度(长度除以段数),长链表的个数(长度处于段数,取余),将原链表直接分割。这里需要注意,可能较长链表分割完之后,链表已经没有节点,短链表长度为0,直接返回即可。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def splitListToParts(self, head: ListNode, k: int) -> List[ListNode]:
        len = 0
        cur = head
        while cur:
            len += 1
            cur = cur.next
        business,  remainder= len // k, len % k
        res = [None] * k

        for i in range(k):
            if not head:
                break
            part_len = business + 1 if i < remainder else business
            res[i] = head
            for _ in range(part_len-1):
                head = head.next
            nex = head.next
            head.next = None
            head = nex
        return res

10、链表元素按奇偶聚集

328. 奇偶链表(Medium)

给一个链表,将奇数下表的元素连成链表,后面连接偶数下表的元素组成的链表。

在这里插入图片描述

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def oddEvenList(self, head: ListNode) -> ListNode:
        if not head or not head.next:
            return head
        odd, even = head, head.next
        evenhead = even
        while even and even.next:
            odd.next = even.next
            odd = even.next
            even.next = odd.next
            even = odd.next
        # print_list(head)
        # print_list(evenhead)
        odd.next = evenhead
        return head

11、分区链表

86. 分隔链表(Medium)
方法一(推荐方法):
维护两个链表,small_head 保存值小于 x 的节点,large_head 保存大于等于 x 的节点,遍历链表构建两链表后,将large_head 链表尾节点指向 large_head 链表的头节点。\

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def partition(self, head: ListNode, x: int) -> ListNode:
        small_head = small_tail = ListNode()
        big_head = big_tail = ListNode()
        cur = head
        while cur:
            if cur.val < x:
                small_tail.next = cur
                small_tail = cur
            else:
                big_tail.next = cur
                big_tail = cur
            cur = cur.next
        
        big_tail.next = None
        small_tail.next = big_head.next
        return small_head.next

方法二:
统计大于等于目标值的元素个数,从前向后遍历每个元素,碰见大于等于目标值的元素就将该元素放置到链表末尾。

# 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 partition(self, head, x):
        p = head
        tail = head
        n = 0
        while p:                # 统计大于等于x的元素个数
            if p.val >= x:
                n += 1
            tail = p
            p = p.next
        
        newhead = ListNode(-1)
        newhead.next = head
        pre = newhead
        cur = head
        sum = 0
        while cur and cur.next:
            nex = cur.next
            if cur.val >= x:    # 大于等于x的元素,挪到尾部
                pre.next = nex
                tail.next = cur
                tail = cur
                cur.next = None
                cur = nex
                sum += 1
                if sum >= n:
                    break
            else:
                pre = cur
                cur = nex
        return newhead.next
        
        """
        :type head: ListNode
        :type x: int
        :rtype: ListNode
        """
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值