LeetCode | 24.两两交换链表中的节点(C语言版)

简介: LeetCode | 24.两两交换链表中的节点(C语言版)

      这次来写一下 LeetCode 的第 24 题,两两交换链表中的节点。

题目描述

       题目直接从 LeetCode 上截图过来,题目如下:

       上面的题就是 两两交换链表中的节点 题目的截图,同时 LeetCode 给出了一个函数的定义,然后要求实现链表两两交换的函数体。函数定义如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* swapPairs(struct ListNode* head){
}

       从定义上看,是一个单链表,单链表只能顺着节点的指针依次找下去,而不能往回找。

问题分析

       这个题目看似简单,其实还是有几个坑在里面的。听我慢慢道来。

       先来看看,链表最初的情况,如下图:

       最初链表的头指向第一个节点,我们首先要交换的是第一个节点和第二个节点,根据指针来看,只要让第一个节点的 next 指向第三个节点,然后让第二个节点的 next 指向第一个节点就可以了。在交换之前,首先要有一个指针(pre)指向第一个节点、还要有一个指针(cur)指向第二个节点,当然再准备一个指针(new)指向第三个节点。有了这些指针,就可以完成我们的交换了,如下图:

aHR0cHM6Ly9tbWJpei5xcGljLmNuL21tYml6X3BuZy9CZnY5c21vSHd0andvNjlHMGxpYnM5S1ZkaWJJdjJ2clhjYlhZNTVLbERmNm1qVkxuZWliV0o5dkpkSVNCMlFUNk9TMjdGNWZ1cTExd2NKM1Nhd3hpY1VpYW9nLzY0MA.png

       当交换完成以后,就接着移动这三个指针,进行下一次的交换。这样就构成了一个循环,怎么来判断是否循环?让 new = head,当 new 为 NULL 或者 new->next 为 NULL 的时候,就说明没有节点或者只剩一个节点了,就不用再交换了,这样循环就结束了。


       以上看似完成了,其实还是有一个问题,我们接着推第二步交换试试。如下图:

       开始第二轮交换的时候,指针的位置是这样的,然后按照前面的指针交换的方式进行交换。图下图:

       交换完后的链表成了这个样子,但是仔细观察,不知道是否观察出了问题。我们的 4 号节点没有办法遍历到了。因为 1 号节点的指针仍然指向着 3 号节点,而经过交换,要把 4 号节点放到 3 号节点的前面。那么,也就是说,除了要完成 3 号节点和 4 号节点的交换,还要修正 1 号节点中 next 的指向。而此时,我们已经没有指针指向 1 号节点了。所以,我们增加一个指针 tmp 来指向 pre 指针就可以了,以后通过 tmp 指针的 next 来修正即可。修正后如下图:


       当以后两个节点交换完成后,将 pre 指针赋值给 tmp 指针即可。

       这样看似完成了,那么还有问题么?问题还是有的,我们的 head 指针一直指向的是 1 号节点,但是实际的链表头节点已经是 2 号节点了。当函数执行完成时,需要返回新的链表头节点,要怎么返回呢?我这里又增加了一个新的指针 result 来记录新的头节点,当循环完成以后,直接返回 result 就可以了。

       上面的步骤就算完成了,几个问题其实都是我在写代码的时候遇到的。虽然步骤是完成了,但是我觉得我的代码应该还是有简化的空间的。暂时没有再去考虑了。

代码实现

       上面说了那么多,其实代码反倒不是很复杂。代码如下:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* swapPairs(struct ListNode* head){
    struct ListNode *new = head;
    struct ListNode *pre = NULL;
    struct ListNode *cur = NULL;
    // 如果链表本身就是空的,那么就直接返回好了
    if (head == NULL) {
        return head;
    }
    // 不管链表有多少节点,只要大于等于两个节点,那么新的链表头都是第二个节点
    struct ListNode *result = head;
    if (head->next != NULL) {
        result = head->next;
    }
    struct ListNode *tmp = NULL;
    while (new != NULL && new->next != NULL) {
        // 设置 pre 和 cur 的位置
        pre = new;
        cur = new->next;
        new = new->next->next;
        // 交换
        pre->next = cur->next;
        cur->next = pre;
        // 这就是在第二次以及以后交换中要修正的部分
        if (tmp != NULL) tmp->next = cur;
        // 为了修正,需要保留当前交换的前一个节点
        tmp = pre;
    }
    return result;
}

      注释是我刚刚加上去的,其实自己整理了一遍,发现思路比当时写的时候清晰了许多。整理和总结真的是挺重要的。

提交结果

       在写完 swapPairs 函数体后,点击右下角的 “执行代码”,然后观察 “输出” 和 “预期结果” 是否一致,一致的话就点击 “提交” 按钮。点击 “提交” 按钮后,系统会使用更多的测试用例来测试我们写的函数体,如果所有的测试用例都通过了,那么就会给出 “通过” 的字样,如果没有通过,会给出失败的那一组测试用例,我们继续修改代码。我们以上代码 “提交” 以后的截图如下:

       我觉得在内存消耗上应该可以更小一些,我为了截这个图,重新提交了代码,在提交代码前还修改了几行代码,内存消耗也由 5.5 MB 变为了 5.4 MB,通过梳理自己还是能找到改进空间,给自己点个赞。

相关文章
|
5月前
【力扣】-- 移除链表元素
【力扣】-- 移除链表元素
56 1
|
5月前
|
程序员 C语言
【C语言】LeetCode(力扣)上经典题目
【C语言】LeetCode(力扣)上经典题目
|
5月前
LeetCode第二十四题(两两交换链表中的节点)
这篇文章介绍了LeetCode第24题的解法,即如何通过使用三个指针(preNode, curNode, curNextNode)来两两交换链表中的节点,并提供了详细的代码实现。
50 0
LeetCode第二十四题(两两交换链表中的节点)
|
5月前
(剑指offer)18、删除链表的节点—22、链表中倒数第K个节点—25、合并两个排序的链表—52、两个链表的第一个公共节点(2021.12.07)
(剑指offer)18、删除链表的节点—22、链表中倒数第K个节点—25、合并两个排序的链表—52、两个链表的第一个公共节点(2021.12.07)
70 0
|
5月前
|
索引
力扣(LeetCode)数据结构练习题(3)------链表
力扣(LeetCode)数据结构练习题(3)------链表
131 0
|
6月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
7月前
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
79 6
|
7月前
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
153 2
|
4月前
|
机器学习/深度学习 人工智能 自然语言处理
280页PDF,全方位评估OpenAI o1,Leetcode刷题准确率竟这么高
【10月更文挑战第24天】近年来,OpenAI的o1模型在大型语言模型(LLMs)中脱颖而出,展现出卓越的推理能力和知识整合能力。基于Transformer架构,o1模型采用了链式思维和强化学习等先进技术,显著提升了其在编程竞赛、医学影像报告生成、数学问题解决、自然语言推理和芯片设计等领域的表现。本文将全面评估o1模型的性能及其对AI研究和应用的潜在影响。
111 1
|
6月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口

热门文章

最新文章