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

一、合并两个有序链表

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;
}
相关推荐
IPdodo全球网络1 分钟前
如何通过网络加速器提升TikTok创作与观看体验
网络·智能路由器·tiktok·tiktok电商·tk直播
dulu~dulu11 分钟前
查缺补漏----用户上网过程(HTTP,DNS与ARP)
网络·网络协议·http
GISer_Jing37 分钟前
内网部署web项目,外网访问不了?只有局域网能访问!怎样解决?
网络·智能路由器
乌龟跌倒38 分钟前
网络层5——IPV6
网络·计算机网络·智能路由器
福楠41 分钟前
[LeetCode] 1137. 第N个泰波那契数
数据结构·c++·算法·leetcode
丶21361 小时前
【网络】HTTP(超文本传输协议)详解
网络·网络协议·http
安 当 加 密1 小时前
【安当产品应用案例100集】029-使用安全芯片保护设备核心业务逻辑
网络·安全·信息安全·数据安全·芯片·加密技术·数据加密集成服务
坚持拒绝熬夜1 小时前
IP协议知识点总结
网络·笔记·网络协议·tcp/ip
超栈1 小时前
蓝桥杯-网络安全比赛题目-遗漏的压缩包
前端·网络·sql·安全·web安全·职场和发展·蓝桥杯
wanhengwangluo2 小时前
DDOS的攻击方式有哪些?
服务器·网络·ddos