【经典算法】LeetCode25:K 个一组翻转链表(Java/C/Python3,Hard)

news2024/11/18 10:25:40

#算法

目录

  • 题目描述
  • 思路及实现
    • 方式一:递归
      • 思路
      • 代码实现
        • Java 版本
        • C 语言版本
        • Python3 版本
      • 复杂度分析
    • 方式二:迭代和原地反转
      • 思路
      • 代码实现
        • Java 版本
        • C 语言版本
        • Python3 版本
      • 复杂度分析
  • 总结
  • 相似题目

  • 标签:链表、递归

题目描述

给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。

你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

示例 1:

输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]
示例 2:

输入:head = [1,2,3,4,5], k = 3
输出:[3,2,1,4,5]
提示:
链表中的节点数目为 n
1 <= k <= n <= 5000
0 <= Node.val <= 1000
进阶:你可以设计一个只用 O(1) 额外内存空间的算法解决此问题吗?

原题:LeetCode 25

思路及实现

方式一:递归

思路

其大致过程可以分解为

  1. 找到待翻转的k个节点(注意:若剩余数量小于 k 的话,则不需要反转,因此直接返回待翻转部分的头结点即可)。
  2. 对其进行翻转。并返回翻转后的头结点(注意:翻转为左闭又开区间,所以本轮操作的尾结点其实就是下一轮操作的头结点)。
  3. 对下一轮 k 个节点也进行翻转操作。
  4. 将上一轮翻转后的尾结点指向下一轮翻转后的头节点,即将每一轮翻转的k的节点连接起来。

示意图

代码实现

Java 版本
/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    /**
     * 反转链表中每个大小为 k 的连续节点的子链表
     * @param head 当前子链表的头节点
     * @param k 指定的连续节点个数
     * @return 反转后的链表的头节点
     */
    public ListNode reverseKGroup(ListNode head, int k) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode tail = head;
        for (int i = 0; i < k; i++) {
            // 如果剩余数量小于 k,则不需要反转。
            if (tail == null) {
                return head;
            }
            tail = tail.next;
        }
        // 反转前 k 个元素
        ListNode newHead = reverse(head, tail);
        // 下一轮的开始的地方就是 tail
        head.next = reverseKGroup(tail, k);
        return newHead;
    }

    /**
     * 反转链表中左闭右开区间的节点
     * @param head 左闭区间的头节点
     * @param tail 右开区间的尾节点
     * @return 反转后的链表的头节点
     */
    private ListNode reverse(ListNode head, ListNode tail) {
        ListNode pre = null;
        ListNode next = null;
        while (head != tail) {
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }
}

说明:
reverseKGroup() 方法用于将链表每个大小为 k 的子列表进行反转。
如果输入的头节点 head 或其下一个节点为空,则无需翻转,直接返回头节点。
使用 tail 指针找到当前子列表的结束节点(即当前子列表的下一组的开始节点)。
如果剩余节点数量不足 k,则无需进行翻转,直接返回头节点。
调用 reverse() 方法反转当前子列表,并得到翻转后的新的头节点 newHead。
通过递归调用 reverseKGroup() 方法,将下一轮的开始位置 tail 作为参数传入。
将当前子列表的头节点 head 的 next 指针指向下一轮的结果,连接翻转后的下一组子列表。
返回翻转后的新的头节点 newHead。

C 语言版本
struct ListNode {
    int val;
    struct ListNode *next;
};

/**
 * 反转以头节点head开始,尾节点为tail前一个节点的链表
 * 返回反转后的链表的头节点
 */
struct ListNode* reverse(struct ListNode* head, struct ListNode* tail) {
    struct ListNode* prev = NULL;
    struct ListNode* curr = head;
    struct ListNode* next = NULL;
    while (curr != tail) {
        next = curr->next;
        curr->next = prev;
        prev = curr;
        curr = next;
    }
    return prev;
}

/**
 * 反转每个大小为k的连续节点子链表
 * 返回修改后的链表的头节点
 */
struct ListNode* reverseKGroup(struct ListNode* head, int k) {
    if (head == NULL || head->next == NULL) {
        return head;
    }
    struct ListNode* tail = head;
    for (int i = 0; i < k; i++) {
        // 如果剩余节点数不足k个,无需反转,直接返回头节点
        if (tail == NULL) {
            return head;
        }
        tail = tail->next;
    }
    // 反转前k个节点
    struct ListNode* newHead = reverse(head, tail);
    // 递归调用反转后续的子链表,并将结果连接到当前子链表的末尾
    head->next = reverseKGroup(tail, k);
    return newHead;
}

说明:
结构体 ListNode 定义了链表节点的结构,包含一个整型变量 val 和一个指向下一个节点的指针 next。
reverse() 函数用于反转以 head 节点为开始,以 tail 节点为前一个节点的子链表,并返回反转后的链表的头节点。
在 reverse() 函数中,使用三个指针 prev、curr 和 next 分别表示前一个节点、当前节点和下一个节点。
在 while 循环中,将当前节点 curr 的 next 指针指向前一个节点 prev,实现反转。
通过更新指针的位置,进行下一次的节点遍历。
返回反转后的链表的头节点 prev。
reverseKGroup() 函数用于反转每个大小为 k 的连续节点的子链表,并返回修改后的链表的头节点。
在 reverseKGroup() 函数中,如果输入的头节点 head 或其下一个节点为空,则无需反转,直接返回头节点。
使用指针 tail 找到当前子链表的结束节点(即当前子链表的下一组的开始节点)。
如果剩余节点数量不足 k,则无需反转,直接返回头节点。
调用 reverse() 函数反转当前子链表,并得到反转后的新头节点 newHead。
递归调用 reverseKGroup() 函数,对剩余的子链表进行反转,并将结果连接到当前子链表的末尾。
返回反转后的新头节点 newHead。

Python3 版本

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

def reverse(head: ListNode, tail: ListNode) -> ListNode:
    """
    反转以head为头节点、tail为尾节点的子链表
    并返回反转后的链表的头节点
    """
    prev = None
    curr = head
    while curr != tail:
        next = curr.next
        curr.next = prev
        prev = curr
        curr = next
    return prev

def reverseKGroup(head: ListNode, k: int) -> ListNode:
    """
    反转每个大小为k的连续子链表
    并返回修改后的链表的头节点
    """
    if not head or not head.next:
        return head
    tail = head
    # 找到子链表的尾节点
    for _ in range(k):
        if not tail:
            return head
        tail = tail.next
    # 反转子链表,并获取反转后的新的头节点
    new_head = reverse(head, tail)
    # 递归调用,将下一组子链表的头节点连接到当前子链表的末尾
    head.next = reverseKGroup(tail, k)
    return new_head

代码说明:
ListNode 类定义了链表节点的结构,包含一个整数类型变量 val 和一个指向下一个节点的指针 next。
reverse() 函数用于反转以 head 节点为开始,以 tail 节点为前一个节点的子链表,并返回反转后的链表的头节点。
在 reverse() 函数中,使用三个指针 prev、curr 和 next 分别表示前一个节点、当前节点和下一个节点。
在 while 循环中,将当前节点 curr 的 next 指针指向前一个节点 prev,实现反转。
通过更新指针的位置,进行下一次的节点遍历。
返回反转后的链表的头节点 prev。
reverseKGroup() 函数用于反转每个大小为 k 的连续节点的子链表,并返回修改后的链表的头节点。
在 reverseKGroup() 函数中,如果输入的头节点 head 或其下一个节点为空,则无需反转,直接返回头节点。
使用指针 tail 找到当前子链表的结束节点(即当前子链表的下一组的开始节点)。
如果剩余节点数量不足 k,则无需反转,直接返回头节点。
调用 reverse() 函数反转当前子链表,并得到反转后的新头节点 new_head。
递归调用 reverseKGroup() 函数,对剩余的子链表进行反转,并将结果连接到当前子链表的末尾。
返回反转后的新头节点 new_head。

复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的长度。每个节点都被遍历一次,每次遍历反转 k 个节点。

  • 空间复杂度:O(n/k),递归调用栈的深度

方式二:迭代和原地反转

思路

迭代和原地反转的方法是通过遍历链表,对每个子链表进行原地反转,然后将反转后的子链表拼接到最终结果中。

代码实现

Java 版本
class Solution {
    /**
     * 反转以 head 为头节点的链表中的前 k 个节点
     * 返回反转后的头节点以及反转后的尾节点
     */
    private ListNode reverseK(ListNode head, int k) {
        ListNode prev = null;
        ListNode curr = head;
        for (int i = 0; i < k; i++) {
            ListNode next = curr.next;
            curr.next = prev;
            prev = curr;
            curr = next;
        }
        return new ListNode[]{prev, head};
    }

    public ListNode reverseKGroup(ListNode head, int k) {
        ListNode dummy = new ListNode(0); // 创建一个虚拟头节点
        dummy.next = head;
        ListNode prev = dummy; // prev 始终指向每个子链表的反转前的最后一个节点
        ListNode curr = head; // curr 用于遍历链表

        while (curr != null) {
            ListNode tail = curr; // tail 保存每个子链表的最后一个节点
            int count = 0; // count 记录当前子链表的长度
            while (curr != null && count < k) {
                curr = curr.next;
                count++;
            }
            if (count < k) {
                // 如果剩余节点数不足 k,则不需要反转,直接跳出循环
                break;
            }
            ListNode[] result = reverseK(tail, k); // 反转当前子链表的前 k 个节点
            ListNode reversedHead = result[0]; // 反转后的头节点
            ListNode reversedTail = result[1]; // 反转后的尾节点

            // 将反转后的子链表接入链表
            prev.next = reversedHead;
            reversedTail.next = curr;
            prev = reversedTail; // 更新 prev 指针
        }

        return dummy.next;
    }
}

说明:
reverseK 方法用于反转以 head 为头节点的链表中的前 k 个节点。返回反转后的头节点和尾节点(这里使用了一个数组来返回多个节点)。
reverseKGroup 方法实现以 k 个一组翻转链表的功能。
创建一个虚拟头节点 dummy 来简化链表操作。
prev 指针始终指向每个子链表的反转前的最后一个节点。
curr 指针用于遍历链表。
使用循环遍历链表,直至 curr 为 null,这样可以处理剩余不足 k 个节点的情况。
在循环中,先找到当前子链表的最后一个节点 tail。
然后,再遍历 k 个节点,通过调用 reverseK 方法来反转这个子链表的前 k 个节点。
获取反转后的头节点 reversedHead 和尾节点 reversedTail。
将反转后的子链表接入链表中,即将 prev 的 next 指向 reversedHead,reversedTail 的 next 指向 curr。
更新 prev 指针,使其指向反转后的尾节点。

C 语言版本

struct ListNode {
    int val;
    struct ListNode *next;
};

/**
 * 反转以 head 为头节点、tail 为尾节点的子链表
 * 并返回反转后的链表的头节点
 */
struct ListNode* reverseLinkedList(struct ListNode* head, struct ListNode* tail) {
    struct ListNode* prev = NULL;
    struct ListNode* curr = head;

    while (curr != tail) {
        struct ListNode* next = curr->next;
        curr->next = prev;
        prev = curr;
        curr = next;
    }
    return prev;
}

/**
 * 按照 k 个一组翻转链表
 * 并返回修改后的链表的头节点
 */
struct ListNode* reverseKGroup(struct ListNode* head, int k) {
    struct ListNode* dummy = malloc(sizeof(struct ListNode)); // 创建一个虚拟头节点
    dummy->val = 0;
    dummy->next = head;
    struct ListNode* prev = dummy; // prev 始终指向每个子链表的反转前的最后一个节点
    struct ListNode* curr = head; // curr 用于遍历链表

    while (curr != NULL) {
        struct ListNode* tail = curr; // tail 保存每个子链表的最后一个节点
        int count = 0; // count 记录当前子链表的长度
        while (curr != NULL && count < k) {
            curr = curr->next;
            count++;
        }
        if (count < k) {
            break; // 如果剩余节点数不足 k,则不需要反转,直接跳出循环
        }
        struct ListNode* reversedHead = reverseLinkedList(tail, curr); // 反转当前子链表
        struct ListNode* reversedTail = tail;

        // 将反转后的子链表接入链表
        prev->next = reversedHead;
        reversedTail->next = curr;
        prev = reversedTail; // 更新 prev 指针
    }

    struct ListNode* newHead = dummy->next;
    free(dummy); // 释放虚拟头节点的内存
    return newHead;
}


说明:
reverseLinkedList 函数用于反转以 head 为头节点,以 tail 为前一个节点的子链表,并返回反转后的链表的头节点。
在 reverseLinkedList 函数中,使用两个指针 prev 和 curr 分别表示前一个节点和当前节点。
在 while 循环中,将当前节点 curr 的 next 指针指向前一个节点 prev,实现反转。
通过更新指针的位置,进行下一次的节点遍历。
返回反转后的链表的头节点 prev。
reverseKGroup 函数实现按照 k 个一组翻转链表的功能。
创建一个虚拟头节点 dummy 并将其指向链表的头部,以便于处理头节点的情况。
使用两个指针 prev 和 curr 分别指向当前子链表的最后一个节点和遍历节点。
在循环中,首先找到当前子链表的末尾节点 tail,然后再遍历 k 个节点。
如果剩余的节点数量不足 k 个,则不需要反转,直接退出循环。
调用 reverseLinkedList 函数反转当前子链表,并获取反转后的头节点 reversedHead 和尾节点 reversedTail。
将反转后的子链表接入链表中,即将 prev 的 next 指针指向 reversedHead,reversedTail 的 next 指针指向 curr。
更新 prev 指针,向后移动到反转后的子链表的尾节点。
返回虚拟头节点 dummy 的 next 指针,即为反转后的链表的头结点。

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

def reverseLinkedList(head: ListNode, tail: ListNode) -> ListNode:
    prev = None
    curr = head

    while curr != tail:
        next_node = curr.next
        curr.next = prev
        prev = curr
        curr = next_node

    return prev

def reverseKGroup(head: ListNode, k: int) -> ListNode:
    dummy = ListNode(0)  # 创建一个虚拟头节点
    dummy.next = head
    prev = dummy  # prev 始终指向每个子链表的反转前的最后一个节点
    curr = head  # curr 用于遍历链表

    while curr:
        tail = curr  # tail 保存每个子链表的最后一个节点
        count = 0  # count 记录当前子链表的长度
        while curr and count < k:
            curr = curr.next
            count += 1
        if count < k:
            break  # 如果剩余节点数不足 k,则不需要反转,直接跳出循环
        reversed_head = reverseLinkedList(tail, curr)  # 反转当前子链表
        reversed_tail = tail

        # 将反转后的子链表接入链表
        prev.next = reversed_head
        reversed_tail.next = curr
        prev = reversed_tail  # 更新 prev 指针

    return dummy.next

说明:
reverseLinkedList 函数用于反转以 head 为头节点、tail 为尾节点的子链表,并返回反转后的链表的头节点。

在 reverseLinkedList 函数中,使用两个指针 prev 和 curr 分别表示前一个节点和当前节点。

在 while 循环中,将当前节点 curr 的 next 指针指向前一个节点 prev,实现反转。

通过更新指针的位置,进行下一次的节点遍历。

返回反转后的链表的头节点 prev。

reverseKGroup 函数用于按照 k 个一组翻转链表。

创建一个虚拟头节点 dummy 并将其指向链表的头部,以便于处理头节点的情况。

使用两个指针 prev 和 curr 分别指向当前子链表的最后一个节点和遍历节点。

在循环中,首先找到当前子链表的末尾节点 tail,然后再遍历 k 个节点。

如果剩余的节点数量不足 k 个,则不需要反转,直接退出循环。

调用 reverseLinkedList 函数反转子链表,并获取反转后的头节点和尾节点。

将反转后的子链表接入链表中,即将 prev 的 next 指针指向反转后的头节点,尾节点的 next 指针指向下一个子链表的头节点。

更新 prev 指针,向后移动到反转后的子链表的尾节点。

复杂度分析

  • 时间复杂度:O(n),其中 n 是链表的长度。每个节点恰好被访问两次:一次是遍历整个链表,一次是进行反转操作。
  • 空间复杂度:O(1)。只使用了常数级别的额外空间来进行指针操作,没有使用额外的数据结构。

总结

递归法迭代+原地反转方法
思路将链表划分为大小为k的子链表,递归处理使用循环迭代遍历链表,并在每次迭代中原地反转子链表
时间复杂度O(n),每个节点被遍历一次O(n),每个节点被遍历一次
空间复杂度O(n/k),递归调用栈的深度O(1),原地修改链表
(如果递归栈的深度达到n/k,则创建了O(n/k)个递归调用栈帧)(不需要额外的空间,仅使用常数级别的指针变量和变量存储空间)
优点实现简单,逻辑清晰不需要额外的递归调用栈,适用于大规模链表
代码可读性好原地修改链表,不需要额外空间
缺点递归调用栈可能溢出实现相对复杂,需要处理指针的连接
额外的空间复杂度需要对子链表进行循环遍历和反转
特点可以处理较小规模的链表适用于大规模链表处理和优化空间复杂度
可读性好,思考和实现过程接近问题描述可读性相对较差,实现相对复杂

相似题目

相似题目力扣链接
反转链表 II力扣92
反转链表力扣206
K个一组翻转链表力扣25

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1573552.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DFS:floodfill算法解决矩阵联通块问题

floodfill&#xff0c;翻译为洪水灌溉&#xff0c;而floodfill算法本质上是为了解决在矩阵中性质相同的联通块问题。 一、图像渲染 . - 力扣&#xff08;LeetCode&#xff09; class Solution { public:int dx[4]{0,0,1,-1};int dy[4]{1,-1,0,0};int prev;//记住初始值int m,…

什么是广播系统语言传输指数 STIPA

基础知识 通过广播系统播放一个确定的信号&#xff08;STIPA 测试信号&#xff09;&#xff0c;再在待测点测量其到达后的质量即可。IEC 60268-16 标准中定义通过单一值表示清晰度结果&#xff0c;0 表示完全无法理解&#xff0c;1 表示完美理解。测量单位是 STI&#xff08;语…

C#探索之路基础夯实篇(3):面向对象的三大特性和五大原则详解

文章目录 前提&#xff1a;一、特性&#xff1a;二、原则&#xff1a;三、示例1. 单一职责原则 (Single Responsibility Principle, SRP)&#xff1a;2. 开放-封闭原则 (Open-Closed Principle, OCP)&#xff1a;3. 里氏替换原则 (Liskov Substitution Principle, LSP)&#xf…

移动硬盘能当u盘重装系统吗?做启动数据还能恢复吗

在数字时代&#xff0c;随着技术的不断发展&#xff0c;我们越来越依赖于各种存储设备&#xff0c;其中移动硬盘以其大容量和便携性受到广大用户的青睐。不过&#xff0c;有时我们可能会遇到需要使用U盘来重装系统的情况&#xff0c;而手头又没有合适的U盘。这时&#xff0c;我…

Spring Boot-01-通过一个项目快速入门

官方参考文档&#xff1a;Spring Boot Reference Documentation 0. 概述 Spring的缺点&#xff1a; 1. 配置繁琐&#xff1a;虽然Spring的组件代码是轻量级&#xff0c;但它的配置却是重量级的。 2. 依赖繁琐&#xff1a;项目的依赖管理也是一件耗时耗力的事情。分析要导入哪…

03-JAVA设计模式-工厂模式详解

工厂模式 工厂设计模式是一种创建型设计模式&#xff0c;它提供了一种封装对象创建过程的机制&#xff0c;将对象的创建与使用分离。 这种设计模式允许我们在不修改客户端代码的情况下引入新的对象类型。 在Java中&#xff0c;工厂设计模式主要有三种形式&#xff1a;简单工厂…

【CNN】ConvMixer探究ViT的Patch Embedding: Patches Are All You Need?

Patches Are All You Need? 探究Patch Embedding在ViT上的作用&#xff0c;CNN是否可用该操作提升性能&#xff1f; 论文链接&#xff1a;https://openreview.net/pdf?idTVHS5Y4dNvM 代码链接&#xff1a;https://github.com/tmp-iclr/convmixer 1、摘要 ViT的性能是由于T…

基于Spark中随机森林模型的天气预测系统

基于Spark中随机森林模型的天气预测系统 在这篇文章中&#xff0c;我们将探讨如何使用Apache Spark和随机森林算法来构建一个天气预测系统。该系统将利用历史天气数据&#xff0c;通过机器学习模型预测未来的天气情况&#xff0c;特别是针对是否下雨的二元分类问题。 简介 Ap…

【unity】【C#】延时调用(协程)和场景管理

文章目录 什么是协程协程的应用 - IEnumerator如何控制协程的暂停协程的另一种写法 - Invoke场景管理 多看代码块中的注释 什么是协程 A coroutine alows vou to spreacwhere it left off on the following anc return control toolinencoeframe. 协程允许您将任务分布在多个帧…

Android14应用启动流程(源码+Trace)

1.简介 应用启动过程快的都不需要一秒钟&#xff0c;但这整个过程的执行是比较复杂的&#xff0c;无论是对手机厂商、应用开发来说启动速度也是核心用户体验指标之一&#xff0c;本文采用Android14源码与perfetto工具进行解析。 源码参考地址&#xff1a;Search trace分析工…

【二分查找】Leetcode 在排序数组中查找元素的第一个和最后一个位置

题目解析 34. 在排序数组中查找元素的第一个和最后一个位置 我们使用暴力方法进行算法演化&#xff0c;寻找一个数字的区间&#xff0c;我们可以顺序查找&#xff0c;记录最终结果 首先数组是有序的&#xff0c;所以使用二分法很好上手&#xff0c;但是我们就仅仅使用上一道题…

第四百四十二回 再谈flutter_launcher_icons包

文章目录 1. 概念介绍2. 使用方法3. 示例代码4. 经验与总结4.1 经验分享4.2 内容总结 我们在上一章回中介绍了"overlay_tooltip简介"相关的内容&#xff0c;本章回中将 再谈flutter_launcher_icons包.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 …

配置vscode链接linux

1.安装 remote SSH 2.按F1 ssh ljh服务器公网ip 3. 选择保存远端host到本地 某位置 等待片刻后 4. 切换到远程资源管理器中 应该可以看到一台电脑&#xff0c;右键在当前窗口链接&#xff0c;输入你的服务器用户密码后电脑变绿说明远程连接成功 5.一定要登陆上云服务器后再…

Day:004(2) | Python爬虫:高效数据抓取的编程技术(数据解析)

正则表达式实战-腾讯新闻 需求&#xff1a; 使用正则获取腾讯新闻标题内容 网站&#xff1a;https://sports.qq.com/ 代码&#xff1a; import reimport requests from fake_useragent import UserAgenturl https://sports.qq.com/ # 构建请求头信息 headers {User-Agent:…

【JavaWeb】Day33.MySQL概述

什么是数据库 数据库&#xff1a;英文为 DataBase&#xff0c;简称DB&#xff0c;它是存储和管理数据的仓库。 像我们日常访问的电商网站京东&#xff0c;企业内部的管理系统OA、ERP、CRM这类的系统&#xff0c;以及大家每天都会刷的头条、抖音类的app&#xff0c;那这些大家所…

前端学习之DOM编程星星点灯案例

这个案例的实现逻辑是当你点击屏幕时&#xff0c;会完成一个事件&#xff0c;在你的屏幕上生成一张星星图片。然后再设置星星图片的大小将其改为随机。 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><t…

K8S基于containerd做容器从harbor拉取镜

实现创建pod时&#xff0c;通过指定harbor仓库里的镜像来运行pod 检查&#xff1a;K8S是不是用containerd做容器运行时&#xff0c;以及containerd的版本是不是小于1.6.22 kubectl get nodes -owide1、如果containerd小于 1.6.22&#xff0c;需要先升级containerd 先卸载旧的…

C/C++预处理过程

目录 前言&#xff1a; 1. 预定义符号 2. #define定义常量 3. #define定义宏 4. 带有副作用的宏参数 5. 宏替换的规则 6. 宏和函数的对比 7. #和## 8. 命名约定 9. #undef 10. 命令行定义 11. 条件编译 12. 头文件的包含 13. 其他预处理指令 总结&#x…

最新高自定义化的AI翻译(沉浸式翻译),可翻译网页和PDF等文件或者文献(附翻译API总结,Deeplx的api,Deepl的api)

前序 常见问题&#xff1a; 1.有时候想翻译网页&#xff0c;又翻译文献怎么办&#xff1f;下两个软件&#xff1f; 2.什么软件可以翻译视频字幕&#xff1f; 3.什么软件可以翻译PDF文件&#xff1f; 沉浸式翻译介绍 可以翻译文献可以翻译视频字幕可以翻译PDF文件支持OpenAI翻译…

7 个 iMessage 恢复应用程序/软件可轻松恢复文本

由于误操作、iOS 升级中断、越狱失败、设备损坏等原因&#xff0c;您可能会丢失 iPhone/iPad 上的 iMessages。意外删除很大程度上增加了这种可能性。更糟糕的是&#xff0c;这种情况经常发生在 iDevice 缺乏备份的情况下。 &#xff08;iPhone消息消失还占用空间&#xff1f;&…