个人技术分享

目录

引言

面试题01:返回倒数第k个节点 

题目描述:

思路分析:

代码展示:

面试题02:链表的回文结构

题目描述:

描述

思路分析:

代码展示:

面试题03:相交链表

题目描述:

思路分析:

代码展示:

小结:


引言

这次的题均来自力扣和牛客有关链表的经典面试题,代码只会展示最优的解法,之前发布过单链表的经典算法--单链表经典算法-CSDN博客,大家可以先看看经典算法,再看这个面试题,会轻松很多,如果觉得这篇博客对你有帮助的话,一定要点赞关注哦!

面试题01:返回倒数第k个节点 

--面试题 02.02. 返回倒数第 k 个节点 - 力扣(LeetCode)

题目描述:

实现一种算法,找出单向链表中倒数第 k 个节点。返回该节点的值。

注意:本题相对原题稍作改动

示例:

输入: 1->2->3->4->5 和 k = 2
输出: 4

说明:

给定的 k 保证是有效的。 

思路分析:

这道题最快的解题方法为快慢指针,大家可以先去看单链表经典算法-CSDN博客中的链表的中间节点.也就是定义两个指针,快指针先走k步,再让快慢指针同时走,直到快指针为NULL,两个指针之间恒定相差为k步,最后的慢指针即为倒数第k个节点.如下图所示:

代码展示:

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


int kthToLast(struct ListNode* head, int k){
    struct ListNode* fast = head, *slow = head;
    //快指针先走k步
    while(k--)
    {
        fast = fast->next;
    }
    //同时走
    while(fast)
    {
        fast = fast->next;
        slow = slow->next;
    }
    return slow->val;
}

面试题02:链表的回文结构

--链表的回文结构_牛客题霸_牛客网 (nowcoder.com)

题目描述:

描述

对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。

给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。

测试样例:

1->2->2->1
返回:true

思路分析:

这道题主要难在它的空间复杂度要求为O(1),也就是不能在创建新的链表,所以重点从如何判断回文结构入手,我们不难发现,找到链表的中间节点,再将链表另一侧翻转,如果两边相同即为回文结构,如下图所示:

这里就涉及了两个算法,一个是找到链表的中间节点并返回,一个是翻转链表.这两个算法大家可以去看单链表经典算法-CSDN博客,哪里我详细讲解了这两个算法的实现,这里我就不多说了,直接给出代码:

代码展示:

找到链表的中间节点

struct ListNode* middleNode(struct ListNode* head) {
    //创建快慢指针
    ListNode*slow = head;
    ListNode*fast = head;
    while(fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}

翻转链表

struct ListNode* reverseList(struct ListNode* head) {
    //判空
    if(head == NULL)
    {
        return head;
    }
    //创建三个指针
    ListNode*n1,*n2,*n3;
    n1 = NULL,n2=head,n3=n2->next;
    while(n2)
    {
        n2->next = n1;
        n1=n2;
        n2=n3;
        //n2没走完时,n3已经为空,要进行判空
        if(n3)
            n3 = n3->next;
    }
    return n1;
}

完整代码:

class PalindromeList {
public:

struct ListNode* reverseList(struct ListNode* head) {
    //判空
    if(head == NULL)
    {
        return head;
    }
    //创建三个指针
    ListNode*n1,*n2,*n3;
    n1 = NULL,n2=head,n3=n2->next;
    while(n2)
    {
        n2->next = n1;
        n1=n2;
        n2=n3;
        //n2没走完时,n3已经为空,要进行判空
        if(n3)
            n3 = n3->next;
    }
    return n1;
}

struct ListNode* middleNode(struct ListNode* head) {
    //创建快慢指针
    ListNode*slow = head;
    ListNode*fast = head;
    while(fast && fast->next)
    {
        slow = slow->next;
        fast = fast->next->next;
    }
    return slow;
}
    bool chkPalindrome(ListNode* A) {
        // write code here
        struct ListNode* mid = middleNode(A);
        struct ListNode* rmid = reverseList(mid);

        while(rmid && A)
        {
            if(rmid->val != A->val)
                return false;

            rmid = rmid->next;
            A = A->next;
        }
        return true;
    }
    
};

面试题03:相交链表

--160. 相交链表 - 力扣(LeetCode)

题目描述:

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

图示两个链表在节点 c1 开始相交:

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

思路分析:

首先题目要求判断两个链表是否相交,若相交返回相交的起始节点,否侧返回NULL,那么第一个问题如何判断两个链表是否相交呢?其实很简单,遍历两个链表,找到两个链表的最后节点,若两个链表的最后节点相等,那么两个链表一定相交.难就难在如何返还相交起始节点的位置,因为两个链表相交之前的链表是不相等的,如果是相等的话,那我们就可以直接遍历,从这个角度出发,我们在之前判断是否相交时,求出两个链表的长度,因为后半段的长度两个链表一直,那么两个链表的长度差即为长链表领先的节点个数,让长链表先走长度差,再让两个链表同时走,这样就能找到起始相交的节点.如下图:

代码展示:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
    struct ListNode* curA = headA, *curB = headB;
    int lenA = 0, lenB = 0;
    while(curA->next)
    {
        curA = curA->next;
        ++lenA;
    }

    while(curB->next)
    {
        curB = curB->next;
        ++lenB;
    }
    //尾节点不相交返回空
    if(curA != curB) return NULL;
    int gap = abs(lenA - lenB);
    struct ListNode* longList = headA, * shortList = headB;
    if(lenB > lenA)
    {
        longList = headB;
        shortList = headA;
    }
    while(gap--)
    {
        longList = longList->next;
    }
    while(longList != shortList)
    {
        longList = longList->next;
        shortList = shortList->next;
    }
    return shortList;
}

小结:

这一个专题我准备分两期进行制作,后一期专门进行链表带环问题的讲解,如果觉得对你有帮助的家人们,记得点赞关注哦!