【数据结构】_链表经典算法OJ:相交链表

目录

1.  题目链接及描述

2.  解题思路

2.1 思路1:一个链表把另外一个链表的结点逐个轮一遍

2.2 思路2:截断长链表,从距离交点结点前等距处开始同时遍历(本题解法)

3. 程序

关于解题程序的细节:

3.1 假设法的应用:

3.2 关于链表长度的计算


1.  题目链接及描述

题目链接:160. 相交链表 - 力扣(LeetCode)

题目描述:

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。
图示两个链表在节点 c1 开始相交:

【数据结构】_链表经典算法OJ:相交链表_第1张图片
题目数据 保证 整个链式结构中不存在环。
注意,函数返回结果后,链表必须 保持其原始结构 。

2.  解题思路

拆解题目要求:1、判断是否相交;2、若相交则找出第一个交点;

判断两个单链表是否相交:判断两个链表的尾指针是否相等,相等则相交,不等则不相交

注:1、本题不可逆置:否则在交点结点处存在两个next指针域,;

一个结点不允许存在两个next指针域;

2、判断尾指针相等与否需要用地址判断,不能用val值判断

2.1 思路1:一个链表把另外一个链表的结点逐个轮一遍

为两个链表分别创建结构体指针curNodeA和curNodeB,用第二个链表的每一个结点依次把第一个链表的所有结点都比一遍,直至交点结点处会相等;

时间复杂度O(N^2);

注:两个指针不可同时走,若相交结点前两个链表长度不同,则会导致即使相交也被判定为不相交的情况;

2.2 思路2:截断长链表,从距离交点结点前等距处开始同时遍历(本题解法)

分别计算两个链表的长度,若长度相等则直接从第一个结点处开始同时遍历并依次对比;

长度不等则截断长链表,从与短链表第一个结点到交点结点前处的结点开始同时遍历并依次对比;

时间复杂度O(N);

3. 程序

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
typedef struct ListNode ListNode;
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    ListNode* curNodeA=headA,*curNodeB=headB;
    // 分别计算两个链表长度
    int lenA=1,lenB=1;
    while(curNodeA->next){
        curNodeA=curNodeA->next;
        lenA++;
    }
    while(curNodeB->next){
        curNodeB=curNodeB->next;
        lenB++;
    }
    // 两个链表直至遍历到尾结点,指针都不等:两个链表不相等;
    if(curNodeA != curNodeB){
        return NULL;
    }
    // 令长链表的遍历指针先走差值步,再同时遍历,第一个相等就是交点
    int gap=abs(lenA-lenB);
    // 假设法:假设A长B短
    ListNode* longList=headA,*shortList=headB;
    // 若假设错误则修正
    if(lenB>lenA){
        longList=headB;
        shortList=headA;
    }
    while(gap--){
        longList=longList->next;
    }
    while(longList != shortList){
        shortList=shortList->next;
        longList=longList->next;
    }
    return shortList;
}

关于解题程序的细节:

3.1 假设法的应用:

当算得两个链表长度后,若链表长度不同,则需要截断长链表。但由于长短链表到底对应A和B哪个链表未知,若采用if(lenA>lenB)和if(lenB>lenA)两大分支则会造成代码的一定重复冗余,可采用假设法:

定义两个结构体变量longList和shortList分别指向长链表和短链表:

先假设A长B短,则将A赋值给LongList,B赋值给shortList。

若假设错误再修正:若lenB>lenA,再将B赋值给LongList,A赋值给shortList;

3.2 关于链表长度的计算

由于需定位到两个链表的尾结点,故循环判断条件应为curNodeX->next而非curNodeX,但当遍历至尾结点时不进入循环,如果将链表长度变量lenX初始值设为0,就会导致链表长度计算少算了尾结点,故而在设定链表长度变量lenX时,将其初始值均设为1;

但其实两个链表的长度即使少算了1,也不会造成影响:链表长度仅用于计算长短链表的差值。

你可能感兴趣的:(OJ,C语言,数据结构(C&C++),算法,数据结构,leetcode)