【8.6】链表-两两交换链表中的节点

目录

一、题目

二、解题思路

2.1 非递归解决

2.1 递归解决

2.3 交换节点的值


 🎬 攻城狮7号个人主页

🔥 个人专栏: 《C/C++算法》

⛺️ 君子慎独!

 🌈 大家好,欢迎来访我的博客!
⛳️ 此篇文章主要讲解算法题目:两两交换链表中的节点
📚 本期文章收录在《C/C++算法》,大家有兴趣可以自行查看!
⛺️ 欢迎各位 ✔️ 点赞 👍 收藏 ⭐留言 📝!

一、题目

        给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。

示例 1:

输入:head = [1,2,3,4]
输出:[2,1,4,3]

示例 2:

输入:head = []
输出:[]

示例 3:

输入:head = [1]
输出:[1]

提示:

  • 链表中节点的数目在范围 [0, 100]
  • 0 <= Node.val <= 100

二、解题思路

2.1 非递归解决

        这道题目主要考察的是链表节点的交换操作。要完成链表的节点交换,首先需要理解如何断开和重新连接链表节点。我们可以将链表分成若干组,每组包含两个节点。首先交换第一组的两个节点,交换完成后,将后面的节点继续分为两组,重复同样的交换操作,直到无法再交换为止。需要注意的是,如果链表可以进行交换,那么原链表的第二个节点将成为新链表的头节点。

        为了更好地理解这个过程,我们可以通过一个示例来画图说明。

#include <iostream>

// 定义链表节点结构体
struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};

ListNode* swapPairs(ListNode* head) {
    // 链表至少有2个节点才能交换,否则直接返回
    if (head == nullptr || head->next == nullptr)
        return head;

    // 定义辅助节点
    ListNode* first = head;
    ListNode* second;
    ListNode* third;
    // 用于记录交换后的尾节点,其 next 需要指向新交换的链表
    ListNode* preLast = nullptr;
    // 新链表的头节点,只赋值一次
    ListNode* newHead = head->next;

    // 只要还有两个节点可以交换,就继续操作
    while (first != nullptr && first->next != nullptr) {
        // 给 second 和 third 赋值
        second = first->next;
        third = second->next;

        // 交换 first 和 second 节点
        first->next = third;
        second->next = first;

        // 如果 preLast 不为空,说明前面还有交换完成的链表
        // 需要让 preLast 的 next 指向新链表的头节点
        if (preLast != nullptr) {
            preLast->next = second;
        }

        // 交换后,first 成为新链表的尾节点,保存到 preLast 中
        preLast = first;

        // 继续操作下一组节点
        first = third;
    }

    // 返回新链表的头节点
    return newHead;
}

// 辅助函数:打印链表
void printList(ListNode* head) {
    ListNode* curr = head;
    while (curr != nullptr) {
        std::cout << curr->val << " ";
        curr = curr->next;
    }
    std::cout << std::endl;
}

int main() {
    // 创建一个示例链表:1 -> 2 -> 3 -> 4
    ListNode* head = new ListNode(1);
    head->next = new ListNode(2);
    head->next->next = new ListNode(3);
    head->next->next->next = new ListNode(4);

    // 调用 swapPairs 函数
    ListNode* result = swapPairs(head);

    // 打印结果链表
    printList(result);

    return 0;
}

2.1 递归解决

        递归的实现需要满足两个关键条件:一是终止条件,二是递归调用自身,二者缺一不可。假设我们通过递归已经将链表中从第三个节点开始的所有节点两两交换完成,那么此时链表可以被分为三个部分:第一个节点、第二个节点以及后面已经交换完成的链表,即 `1 → 2 → 3` 的形式。接下来,我们只需要交换第一个节点和第二个节点的位置,整个链表的节点两两交换就完成了。下面我们通过代码来具体实现这一过程。

#include <iostream>

// 定义链表节点结构体
struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};

ListNode* swapPairs(ListNode* head) {
    // 边界条件判断:如果链表为空或只有一个节点,直接返回
    if (head == nullptr || head->next == nullptr)
        return head;

    // 递归交换从第三个节点开始的所有节点
    ListNode* third = swapPairs(head->next->next);

    // 交换前两个节点
    ListNode* second = head->next;
    head->next = third;
    second->next = head;

    // 返回新的头节点
    return second;
}

// 辅助函数:打印链表
void printList(ListNode* head) {
    ListNode* curr = head;
    while (curr != nullptr) {
        std::cout << curr->val << " ";
        curr = curr->next;
    }
    std::cout << std::endl;
}

int main() {
    // 创建一个示例链表:1 -> 2 -> 3 -> 4
    ListNode* head = new ListNode(1);
    head->next = new ListNode(2);
    head->next->next = new ListNode(3);
    head->next->next->next = new ListNode(4);

    // 调用 swapPairs 函数
    ListNode* result = swapPairs(head);

    // 打印结果链表
    printList(result);

    return 0;
}

2.3 交换节点的值

        另一种解决思路是,由于交换链表节点需要频繁地断开和重新连接,操作较为复杂,因此我们可以选择不交换节点本身,而是直接交换节点中存储的值。这种方法实现起来更加简单,同时也能够达到相同的效果。

#include <iostream>

// 定义链表节点结构体
struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};

ListNode* swapPairs(ListNode* head) {
    int first;
    ListNode* temp = head;

    // 遍历链表,交换每对相邻节点的值
    while (temp != nullptr && temp->next != nullptr) {
        // 直接交换节点的值
        first = temp->val;
        temp->val = temp->next->val;
        temp->next->val = first;

        // 移动到下一对节点
        temp = temp->next->next;
    }

    // 返回链表头节点
    return head;
}

// 辅助函数:打印链表
void printList(ListNode* head) {
    ListNode* curr = head;
    while (curr != nullptr) {
        std::cout << curr->val << " ";
        curr = curr->next;
    }
    std::cout << std::endl;
}

int main() {
    // 创建一个示例链表:1 -> 2 -> 3 -> 4
    ListNode* head = new ListNode(1);
    head->next = new ListNode(2);
    head->next->next = new ListNode(3);
    head->next->next->next = new ListNode(4);

    // 调用 swapPairs 函数
    ListNode* result = swapPairs(head);

    // 打印结果链表
    printList(result);

    return 0;
}

        总结:在链表的节点交换过程中,确实需要在交换前两个节点之前,先将第三个节点保存起来,否则交换完成后会丢失对第三个节点的引用。

看到这里了还不给博主点一个:
⛳️ 点赞☀️收藏 ⭐️ 关注

💛 💙 💜 ❤️ 💚💓 💗 💕 💞 💘 💖
再次感谢大家的支持!
你们的点赞就是博主更新最大的动力!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

攻城狮7号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值