LeetCode 每周算法 4(链表)

LeetCode 每周算法 4(链表)

链表算法:

在这里插入图片描述

# 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, list1, list2):
        """
        :type list1: Optional[ListNode]
        :type list2: Optional[ListNode]
        :rtype: Optional[ListNode]
        """
        # 创建一个哨兵节点,哨兵节点的作用是简化头节点可能为空的处理  
        # 新链表的头节点将会是哨兵节点的下一个节点  
        prehead = ListNode(-1)

        # pre 指针用于构建新链表,初始时指向哨兵节点  
        pre = prehead

        # 当list1和list2都不为空时,循环比较它们的值  
        while list1 and list2:
            # 如果list1的值较小或等于list2的值,则将list1的当前节点接入新链表  
            if list1.val <= list2.val:
                pre.next = list1
                list1 = list1.next # 移动list1到下一个节点  
            else:
                # 如果list2的值较小,则将list2的当前节点接入新链表  
                pre.next = list2
                list2 = list2.next # 移动list2到下一个节点
            # pre指针也移动到新接入的节点,以便接入下一个节点
            pre = pre.next

        # 如果l1或l2中还有剩余节点,直接将剩余部分接入新链表  
        # 注意:这里不需要再比较了,因为已经保证了是升序的  
        pre.next = list1 if list1 is not None else list2

        # 返回新链表的头节点(哨兵节点的下一个节点)
        return prehead.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 addTwoNumbers(self, l1, l2):
        """
        :type l1: ListNode
        :type l2: ListNode
        :rtype: ListNode
        """
        # 初始化结果链表的头节点,初始时不存储任何值(val=0)  
        dummy = ListNode(0)  
        # 使用一个指针来遍历结果链表  
        current = dummy  
        # 初始化进位为0  
        carry = 0  
    
        # 当l1和l2都不为空时,进行循环  
        while l1 is not None or l2 is not None:  
            # 分别获取l1和l2当前节点的值,如果为空则视为0  
            x = l1.val if l1 is not None else 0  
            y = l2.val if l2 is not None else 0  
            
            # 计算当前位的和(包括进位)  
            sum = carry + x + y  
            
            # 更新进位  
            carry = sum // 10  
            
            # 创建新节点存储当前位的值(对10取余)  
            current.next = ListNode(sum % 10)  
            
            # 移动指针和链表指针  
            current = current.next  
            if l1 is not None:  
                l1 = l1.next  
            if l2 is not None:  
                l2 = l2.next  
    
        # 如果循环结束后还有进位,则创建一个新节点存储进位  
        if carry > 0:  
            current.next = ListNode(carry)  
    
        # 返回结果链表的头节点的下一个节点(跳过初始的dummy节点)  
        return dummy.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 removeNthFromEnd(self, head, n):
        """
        :type head: ListNode
        :type n: int
        :rtype: ListNode
        """
        # 创建一个哨兵节点,它的next指向链表的头节点  
        # 哨兵节点的作用是简化头节点被删除的情况  
        dummy = ListNode(0)  
        dummy.next = head  
        
        # 初始化两个指针,都指向哨兵节点  
        # fast指针会先走n+1步,这样fast和slow之间就隔了n个节点  
        fast = slow = dummy  
        
        # fast指针先走n+1步  
        for _ in range(n + 1):  
            fast = fast.next  
        
        # 当fast指针到达链表末尾时,slow指针指向倒数第n+1个节点  
        while fast:  
            fast = fast.next  
            slow = slow.next  
        
        # 删除倒数第n个节点  
        # 注意,此时slow指向的是倒数第n+1个节点,所以我们需要删除的是slow.next  
        slow.next = slow.next.next  
        
        # 返回链表的头节点(实际上是哨兵节点的next,即原链表的头节点)  
        return dummy.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 swapPairs(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        # 创建一个哑节点(dummy node),它的next指向链表的头节点  
        # 使用哑节点可以简化对链表头部操作的处理  
        dummy = ListNode(0)  
        dummy.next = head  
        
        # 初始化两个指针,pre指向哑节点,curr指向链表的头节点  
        # pre用于在交换过程中保持对交换前curr节点的前一个节点的引用  
        pre, curr = dummy, head  
        
        while curr and curr.next:  # 当curr和curr.next都不为空时,继续循环  
            # 缓存curr的下一个节点,因为交换后curr.next会改变  
            first = curr  
            second = curr.next  
            
            # 开始交换  
            # 第一步:curr的next指向second的next  
            curr.next = second.next  
            # 第二步:second的next指向first,实现second和first的交换  
            second.next = first  
            # 第三步:pre的next指向second,这样pre->second->first就形成了新的链接  
            pre.next = second  
            
            # 更新pre和curr,以便进行下一对节点的交换  
            pre = first  
            curr = curr.next  
        # 循环结束后,dummy.next将是新的头节点  
        return dummy.next 

在这里插入图片描述

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = 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 reverseKGroup(self, head, k):
        """
        :type head: ListNode
        :type k: int
        :rtype: ListNode
        """
        # 定义一个哑节点,其next指向链表的头节点,用于简化边界条件的处理  
        dummy = ListNode(0)  
        dummy.next = head  
        
        # 初始化pre和tail指针,都指向哑节点,pre用于记录翻转前k个节点组的前一个节点,tail用于遍历检查节点数  
        pre = tail = dummy  
        
        # 使用一个无限循环来处理整个链表,直到tail为空(即链表遍历完成)  
        while True:  
            count = k  # 初始化计数器,用于检查接下来的节点数是否足够k个  
            # 使用while循环来移动tail指针,直到它指向第k个节点或链表末尾  
            while count and tail:  
                count -= 1  
                tail = tail.next  
            # 如果tail为空,说明剩余节点不足k个,跳出循环  
            if not tail:  
                break  
            
            # head指向当前要翻转的k个节点组的第一个节点(即pre.next)  
            head = pre.next  
            
            # 开始翻转这k个节点  
            # 当pre.next不是tail时,说明还有节点需要翻转  
            while pre.next != tail:  
                current = pre.next  # current指向当前要处理的节点(即翻转前的第一个节点)  
                # 将pre的next指向current的next,这样cur就被“断开”了  
                pre.next = current.next  
                # 将current的next指向tail的next,即将current连接到翻转后的链表末尾  
                current.next = tail.next  
                # 将tail的next指向current,即将current插入到tail之前  
                tail.next = current  
            
            # 更新pre和tail的位置,为下一轮翻转做准备  
            # pre移动到翻转后的最后一个节点(即翻转前的第一个节点)  
            pre = head  
            # tail重新指向pre(因为翻转后,pre现在是这一组k个节点的末尾)  
            # 但实际上,由于下一轮循环会重新检查并移动tail,这里直接设为head也是可以的  
            # 不过为了保持代码的一致性,这里仍然设为pre(即翻转后的最后一个节点)  
            tail = pre  
        
        # 返回翻转后的链表的头节点(哑节点的next)  
        return dummy.next

在这里插入图片描述

"""
# Definition for a Node.
class Node:
    def __init__(self, x, next=None, random=None):
        self.val = int(x)
        self.next = next
        self.random = random
"""

class Solution(object):
    def copyRandomList(self, head):
        """
        :type head: Node
        :rtype: Node
        """
        if not head:  # 如果链表为空,则直接返回None  
            return None  
        
        # 步骤1: 复制节点并插入到原节点之后  
        curr = head  
        while curr:  
            newNode = Node(curr.val, curr.next)  # 创建一个新节点,其值与原节点相同,next暂时指向原节点的next  
            curr.next = newNode  # 将原节点的next指向新创建的节点,实现交错链表  
            curr = newNode.next  # 移动到原链表的下一个节点  
        
        # 步骤2: 设置随机指针  
        curr = head  # 重新从头节点开始遍历交错链表  
        while curr:  
            if curr.random:  # 如果原节点有random指针  
                curr.next.random = curr.random.next  # 则新节点的random指针指向原节点random指针的下一个节点(即其副本)  
            curr = curr.next.next if curr.next else None  # 如果当前节点(原节点)有next,则移动到下一个原节点;否则,退出循环  
        
        # 步骤3: 分离链表并恢复原链表  
        dummy = Node(0)  # 创建一个哑节点,用于作为新链表的头节点的前驱  
        prev = dummy  # prev用于追踪新链表的最后一个节点  
        curr = head  # 从头节点开始遍历交错链表  
        while curr:  
            currCopy = curr.next  # curr.next是当前原节点的副本  
            curr.next = currCopy.next  # 恢复原链表的next指针  
            prev.next = currCopy  # 将新链表的最后一个节点的next指向当前副本节点,构建新链表  
            prev = currCopy  # 更新prev为当前副本节点,以便连接到下一个副本节点  
            curr = curr.next  # 移动到原链表的下一个节点  
        
        return dummy.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 sortList(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        def sortFunc(head: ListNode, tail: ListNode) -> ListNode:
            if not head:
                return head
            slow = fast = head
            while fast != tail:
                slow = slow.next
                fast = fast.next
                if fast != tail:
                    fast = fast.next
            mid = slow
            return merge(sortFunc(head, mid), sortFunc(mid, tail))

        def merge(head1: ListNode, head2: ListNode) -> ListNode:
            dummyHead = ListNode(0)
            temp, temp1, temp2 = dummyHead, head1, head2
            while temp1 and temp2:
                if temp1.val <= temp2.val:
                    temp.next = temp1
                    temp1 = temp1.next
                else:
                    temp.next = temp2
                    temp2 = temp2.next
                temp = temp.next
            if temp1:
                temp.next = temp1
            else temp2:
                temp.next = temp2
            return dummyHead.next

        return sortFunc(head, None)

在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        // 如果链表数组为空,则直接返回空指针
        if (lists.size() == 0) return {};

        // 使用lambda表达式定义一个最小堆的比较函数
        priority_queue pq(lists.end(), lists.end(), [](ListNode* l, ListNode* r){return l->val > r->val;});
        
        // 将所有非空链表的头节点加入堆中
        for (const auto& node: lists) if (node) pq.push(node);

        // 创建一个虚拟头节点,用于简化边界条件的处理
        ListNode* dummy = new ListNode;
        ListNode* curr = dummy;

        // 当堆不为空时,持续合并链表 
        while(!pq.empty()) {
            // 取出堆顶元素(当前最小值) 
            curr->next = pq.top();
            pq.pop();

            // 移动当前指针  
            curr = curr->next;

            // 如果取出的节点有下一个节点,则将其加入堆中
            if (curr->next) pq.push(curr->next);
        }
        // 返回合并后的链表的头节点(跳过虚拟头节点)
        return dummy->next;
    }
};

在这里插入图片描述

class DLinkedNode:  
    def __init__(self, key=0, value=0):  
        self.key = key  # 节点存储的键  
        self.value = value  # 节点存储的值  
        self.prev = None  # 指向前一个节点的指针  
        self.next = None  # 指向后一个节点的指针  
  
class LRUCache:  
  
    def __init__(self, capacity: int):  
        self.cache = dict()  # 用于存储键和对应节点的映射  
        self.head = DLinkedNode()  # 虚拟头节点  
        self.tail = DLinkedNode()  # 虚拟尾节点  
        self.head.next = self.tail  # 头节点指向尾节点,表示空链表  
        self.tail.prev = self.head  # 尾节点指回头节点  
        self.capacity = capacity  # 缓存的容量  
        self.size = 0  # 当前缓存中的节点数  
  
    def get(self, key: int) -> int:  
        if key not in self.cache:  # 如果缓存中不存在该键  
            return -1  # 返回-1表示未找到  
        node = self.cache[key]  # 获取对应的节点  
        self.moveToHead(node)  # 将该节点移动到链表头部,表示最近被访问  
        return node.value  # 返回节点的值  
  
    def put(self, key: int, value: int) -> None:  
        if key not in self.cache:  # 如果缓存中不存在该键  
            node = DLinkedNode(key, value)  # 创建新节点  
            self.cache[key] = node  # 将新节点加入缓存映射  
            self.addToHead(node)  # 将新节点添加到链表头部  
            self.size += 1  # 缓存大小加1  
            if self.size > self.capacity:  # 如果超出容量  
                removed = self.removeTail()  # 移除链表尾部的节点  
                self.cache.pop(removed.key)  # 从缓存映射中移除该键  
                self.size -= 1  # 缓存大小减1  
        else:  # 如果缓存中已存在该键  
            node = self.cache[key]  # 获取对应的结点
            node.value = value  # 更新节点的值  
            self.moveToHead(node)  # 将节点移动到链表头部,表示最近被访问  
  
    def addToHead(self, node):  
        node.prev = self.head  # 新节点的前一个节点指向头节点  
        node.next = self.head.next  # 新节点的后一个节点指向头节点的下一个节点  
        self.head.next.prev = node  # 更新头节点的下一个节点的前一个节点为新节点  
        self.head.next = node  # 更新头节点的下一个节点为新节点  
  
    def removeNode(self, node):  
        node.prev.next = node.next  # 更新前一个节点的后一个节点为新节点的后一个节点  
        node.next.prev = node.prev  # 更新后一个节点的前一个节点为新节点的前一个节点  
  
    def moveToHead(self, node):  
        self.removeNode(node)  # 先从链表中移除节点  
        self.addToHead(node)  # 再将节点添加到链表头部  
  
    def removeTail(self):  
        node = self.tail.prev  # 获取链表尾部的实际节点(跳过虚拟尾节点)  
        self.removeNode(node)  # 从链表中移除该节点  
        return node  # 返回被移除的节点



# Your LRUCache object will be instantiated and called as such:
# obj = LRUCache(capacity)
# param_1 = obj.get(key)
# obj.put(key,value)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值