数据结构面试题及答案+字节跳动+滴滴+腾讯高频面试题之链表专题(一)

高频面试题之链表专题(一)

本节目标

  • 1、合并两个有序单链表,要求合并后依旧有序。(2020年字节跳动一面原题)
  • 2、查找单链表的倒数第K个节点。(2020年滴滴一面原题)
  • 3、判断两个单链表是否相交?若相交,求出交点。(2020年腾讯一面原题)
  • 4、判断单链表是否带环?若带环,求出环的长度?若带环求出环的入口点。(2020年腾讯一面原题)

在这里插入图片描述

1、合并两个有序单链表,要求合并后依旧有序。

OJ链接

高频考察的大厂云图:

在这里插入图片描述

解题思路:

先创建一个空链表头节点,然后依次从两个有序链表中选取最小的进行尾插操作进行合并。

在这里插入图片描述

代码实现:
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if(l1 == NULL)
            return l2;
        else if(l2 == NULL)
           return l1;
             
        ListNode* head = NULL, *tail = NULL;
        //创建空链表的头,方便下面进行尾插
    	head = tail = new ListNode;
        while(l1 && l2)
        {
            // 取小的进行尾插
            if(l1->val < l2->val)
            {
                tail->next = l1;
                tail = tail->next;

                l1 = l1->next;
            }
            else
            {
                tail->next = l2;
                tail = tail->next;

                l2 = l2->next;
            }
        }
    
        //其中一个链表剩余节点挂到后面
        if(l1)
            tail->next = l1;
        else
            tail->next = l2;

        ListNode* list = head->next;
        delete head;
        
        return list;
    }
};

2、查找单链表的倒数第K个节点。

OJ链接:

高频考察的大厂云图:

在这里插入图片描述

解题思路:

快慢指针法 fast, slow, 首先让fast先走k步,然后fast,slow同时走,fast走到末尾时,slow走到倒数第k个节点。

在这里插入图片描述

代码实现:
/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        ListNode* slow = pListHead;
        ListNode* fast = slow;
        // 让fast指针先走K步,跟slow指针拉开K步的差距
        while(k--)
        {
            // 这里需要注意链表可能没有K步长
            if(fast)
                fast = fast->next;
            else
                return NULL;
        }
        
        // fast到尾时,slow指向倒数第k个
        while(fast)
        {
            slow = slow->next;
            fast = fast->next;
        }
         
        return slow;
    }
};

3、判断两个单链表是否相交?若相交,求出交点。

OJ链接

高频考察的大厂云图:

在这里插入图片描述

解题思路:
  1. 若两个链表的最后一个节点的指针相同,则相交。
  2. 计算出两个链表的长度,让指向长链表指针先走他们之间的长度差,然后长链表和短链表指针同时走,第一个节点指针相同的点就是交点。

在这里插入图片描述
在这里插入图片描述

代码实现:
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int lenA = 0, lenB = 0;
        ListNode* curA = headA, *curB = headB;
        //先计算两个链表的长度
        while(curA) {
            ++lenA;
            curA = curA->next;
        }
        
        while(curB) {
            ++lenB;
            curB = curB->next;
        }
        
        int gap = abs(lenA-lenB);
        struct ListNode* longList = headA, *shortList = headB;
        if(lenA < lenB) {
            longList = headB;
            shortList = headA;
        }

        //让长链表先走他们之间的长度差
        while(gap--) {
            longList = longList->next;
        }

        //两个链表同时走,直到遇到相同的节点
        while(longList && shortList)  {
            if(longList == shortList) {
                return longList;
            }
            else {
                longList = longList->next;
                shortList = shortList->next;
            }
        }
        
        return NULL;
    }
};

4、判断单链表是否带环?若带环,求出环的长度?若带环,求出环的入口点。

判断带环的OJ链接:https://leetcode-cn.com/problems/linked-list-cycle/

求环的入口点OJ链接:https://leetcode-cn.com/problems/linked-list-cycle-ii/

高频考察的大厂云图:

在这里插入图片描述

解题思路:

在这里插入图片描述

  1. 定义快慢指针fast,slow, fast指针一次走2步,slow指针一次走1步,如果链表确实有环,slow指针进入环以后,fast指针一定会在环内追上slow指针。
  2. 针对上一个问题,面试官通常会加餐:请证明slow指针一次走1步,fast指针一次走2步,为什么一定能追上而不会错过。那么slow走1步,fast走3步呢?那么slow走1步,fast走4步呢?
  3. 求环的长度很好求,从相遇点再走一圈就可以求出来了。
  4. 求环的入口点请看下面的证明。

在这里插入图片描述

公式推导如上图所示, 如果链表存在环,则fast和slow会在环内相遇,定义相遇点到入口点的距离为X,定义环的长度为C,链表头到入口点的距离为L,slow进入环之前,fast已经在环中跑了N圈了,fast在slow进入环之后一圈内追上slow,则会得知:
slow所走的步数为:L + X
fast所走的步数为:L + X + N * C
并且fast所走的步数为slow的两倍,故:
2*(L + X) = L + X + N * C
即: L = N * C - X
所以从相遇点开始slow继续走,让一个指针从头开始走,相遇点即为入口节点

代码实现:
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode* slow = head;
        ListNode* fast = head;

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

            if(slow == fast)
                return true;
        }

        return false;
    }
};
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* slow = head;
        ListNode* fast = head;

        while(fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;
            //走到相遇点
            if(slow == fast)
            {
                // start从链表的头开始走,meet从相遇点开始走,第一次碰到的点就是入口点,这是上面的公式证明出来的
                ListNode* meet = slow;
                ListNode* start = head;

                while(meet != start)
                {
                    meet = meet->next;
                    start = start->next;
                }

                return meet;
            }
        }

        return NULL;
    }
};

上述的内容,如果你没有明白的地方,这是我们录制的视频讲解,请参考

如果你对我写的内容感兴趣,并且对你有帮助,请你点个赞哦
你对哪些面试题感兴趣,你可以留言,我们会出视频,带你学习哦~
在这里插入图片描述

posted @ 2020-05-31 13:08  好好学习天天编程  阅读(390)  评论(0编辑  收藏  举报