数据结构 | 题目练习第二章 | 合并两个有序链表 | 环形链表 | 环形链表入环第一个节点

一、合并两个有序链表

21. 合并两个有序链表

思路一

从头开始,取两个链表中小的那个尾插到新链表

c 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) {
    // 首先判断链表是否为空
    if(l1 == NULL){
        return l2;
    }

    if(l2 == NULL){
        return l1;
    }

    struct ListNode* head = NULL,*tail = NULL;

    while(l1 != NULL && l2 != NULL){
        
        // 如果l1的val小于l2的val就将l1的val尾差
        if(l1->val < l2->val){
            // 第一个tail是为NULL
             if(tail == NULL){
                head = tail = l1; 
             }
             else{
                // tail 已经有节点,连接下一个节点
                tail->next = l1;
                // 并且tail往后面走
                tail =  tail->next;
             }
             // 同时l1插入后到下一个节点
             l1 = l1->next;
        }else{ // 这里就是l2小了
             if(tail == NULL){
                head = tail = l2; 
             }
             else{
                tail->next = l2;
                tail =  tail->next;
             }
             l2 = l2->next;
        }
    }
    // 不一定同时结束,判断谁还有剩余,将剩余的连接到后面
    if(l1)
        tail->next = l1;

    if(l2)
        tail->next = l2;

    return head;
}
  • 优化后
c 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) {

        struct ListNode* head = NULL,*tail = NULL;
    
    // 1.首先判断链表是否为空
    if(l1 == NULL){
        return l2;
    }

    if(l2 == NULL){
        return l1;
    }

    // 1.1可以首先取一个做头
    if(l1->val < l2->val){
        
        head = tail = l1;
        l1 = l1->next;
    }else{
        head = tail = l2;
        l2 = l2->next;  
    }
    //1.2或者开辟一个哨兵位
    // head = tail = (struct ListNode*)malloc(sizeof(struct ListNode));
    // 但是注意返回值 head,需要返回第一个头,而不是哨兵位
    // struct ListNode* first = head->next;
    // free(head);
    // return first;

    while(l1 != NULL && l2 != NULL){
        // 如果l1的val小于l2的val就将l1的val尾差
        if(l1->val < l2->val){
                tail->next = l1;
                l1 = l1->next;
        }else{ // 这里就是l2小了
                tail->next = l2;
                l2 = l2->next;
        }
          tail =  tail->next;
    }
    // 不一定同时结束,判断谁还有剩余,将剩余的连接到后面
    if(l1)
        tail->next = l1;

    if(l2)
        tail->next = l2;

    return head;
}

二、环形链表

141. 环形链表

思路一:快慢指针

其他问题

  1. 请证明slow和fast一定会在环里相遇?有没有可能永远跟不上?(slow一次走一步,fast一次走两步)

:slow进环了以后,fast正式开始追了,假设fast和slow之间的距离是N,追的过程中,他们的距离是如何变化的?

N fast追slow的过程中距离每次缩小1

N-1

N-2 距离是0的时候就相遇

  1. slow走一步,fast走3步行不行?slow走一步,fast走4步行不行?... 请证明

:slow走一步,fast走3步,不一定能追上,甚至可能会死循环,永远追不上

会出现下面两种可能性:

  • 0代表相遇
  • -1代表fast反超了slow,那么进入新的追逐,他们之间的距离是C-1(假设C是环的长度),
  • 如果C-1是偶数 就能追上,如果C-1是奇数就永远追不上;因为每次距离减少2
  • 距离是奇数就意味着快追上时,距离又会是-1,然后fast反超slow,这里距离又是C-1,那么就死循环了,永远追不上。
c 复制代码
N									N
N-2									N-2
N-4									N-4
N-6									N-6
... 								... 
0									-1
如果N是偶数							如果N是奇数
  • slow走一步,fast走4步也是同理:
  • 相当于是3的倍数才会为0,如果不是距离就可能是-1,-2,所以说距离只要不是3的倍数就追不上。
c 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struc t ListNode *head) {
    struct ListNode* slow = head,*fast = head;

    while(fast && fast->next){
        
        slow = slow->next;
        fast = fast->next->next;

        // 如果相遇就返回true
        if(slow == fast){
                return true;
        }
    }
    // 如果循环完毕,还没有等于就没有带环
        return false;
}

三、环形链表2

142. 环形链表 II

思路:一个指针从meet点开始走,一个指针从链表起始点走,他们会在入口点相遇

推导过程

c 复制代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *detectCycle(struct ListNode *head) {
    struct ListNode* slow  = head,*fast = head;
    while(fast && fast->next){

        slow = slow->next;
        fast = fast->next->next;

        // 推导的结论:一个指针从相遇点meet开始走,一个指针从head走,他们会在入口点相遇
        if(slow == fast){
            struct ListNode* meet = slow;
            while(head != meet){
                // 他们没有相等则继续往下走
                    head = head->next;
                    meet = meet->next;
            }
            // 退出循环则相遇
            return meet;
        }
    }
    // 表示无环等于空
    return NULL;
}
相关推荐
振浩微433射频芯片31 分钟前
从门锁到考勤,VRC522B如何在近场读卡场景中“稳坐C位”?
网络·人工智能·单片机·物联网
kkkkkkkkkk_Z7 小时前
学嵌入式和C语言编程数据结构|学习日记Day22:栈,二叉树,哈希存储
c语言·数据结构·学习
码行山野赴时序归途7 小时前
三道经典数组题:从暴力到最优的算法思维
c语言·开发语言·数据结构·算法·leetcode
Logintern098 小时前
网络通讯协议—TCP/IP协议
网络·网络协议·tcp/ip
熊IT10 小时前
什么是原生住宅 IP?如何判断一个 IP 是否真正“原生”?
服务器·网络·tcp/ip
爱学习的小白柏10 小时前
【AI问数技术】多Agent协同架构:查询规划/SQL生成/洞察分析/报告生成
java·网络·人工智能·windows·sql·架构·llama
土司大王12 小时前
LeetCode hot100——合并两个有序链表
算法·leetcode·链表
码行山野赴时序归途12 小时前
算法效率的度量(上):时间复杂度中的对数思维
c语言·数据结构·算法
格尔曼Noah13 小时前
iPhone共享网络给电脑的方式
网络·电脑·iphone
一木 之林14 小时前
四、STL容器与数据结构
开发语言·数据结构·c++