您现在的位置是:首页 >其他 >代码随想录算法训练营第四天|24.两两交换链表中的结点 19.删除链表倒数第n个结点 02.07.链表相交 142.环形链表II网站首页其他

代码随想录算法训练营第四天|24.两两交换链表中的结点 19.删除链表倒数第n个结点 02.07.链表相交 142.环形链表II

禹泽. 2023-06-08 16:00:03
简介代码随想录算法训练营第四天|24.两两交换链表中的结点 19.删除链表倒数第n个结点 02.07.链表相交 142.环形链表II

目录

LeeCode 24.两两交换链表中的结点

LeeCode 19.删除链表倒数第n个结点

LeeCode 02.07.链表相交

LeeCode 142.环形链表II

总结


LeeCode 24.两两交换链表中的结点

力扣题目链接

思路:

题目要求不能改变结点内部值,故通过改变指针来完成交换操作。如下图所示——

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
    	ListNode* dummyHead = new ListNode(0);
		dummyHead->next = head;
		ListNode* cur = dummyHead;
		while(cur->next != NULL && cur->next->next != NULL){
			ListNode* tmp = cur->next;
			ListNode* tmp1 = cur->next->next->next;
			cur->next = cur->next->next;
			cur->next->next = tmp;
			cur->next->next->next = tmp1;
			cur = cur->next->next;
		} 
		return dummyHead->next;
    }
};

时间复杂度:O(n)     空间复杂度:O(1)


LeeCode 19.删除链表倒数第n个结点

力扣题目链接

思路:设置虚拟头结点,左右指针指向头结点,先将右指针右移n个单位,再将左右指针同时右移直至右指针指向链尾,此时左指针指向倒数第n-1的位置,执行删除倒数第n个结点的操作。 

class Solution {
public:
    ListNode *removeNthFromEnd(ListNode *head, int n) {
        ListNode *dummy = new ListNode(0, head);
        ListNode *left = dummy, *right = dummy;
        while (n--)
            right = right->next;
            //此时right和left相距n个单位长度 
        while (right->next) {
            left = left->next;
            right = right->next;
        }   //因为两个指针同时同向移动,故距离保持n不变
		    //当right移动到链表尾端时,left移动到 倒数第n-1 位置处
		LinkNode* tmp = left->next;	 
        left->next = left->next->next; 
        delete tmp;
		return dummy->next;
    }
};

时间复杂度:O(n)     空间复杂度:O(1)


LeeCode 02.07.链表相交

力扣题目链接

思路:两个链表若相交,说明有一结点同时存在于两个链表上,如图——

 

链表AD和链表BD在C点相交,若想找出来相交的点,需先走完AB'段,然后在B'D和BD段寻找是否有相同的结点。

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
    	ListNode* curA = headA;
    	ListNode* curB = headB;
    	int lenA = 0,lenB = 0;
        //求两个链表的长度
		while(curA != NULL){
    		lenA++;
    		curA = curA->next;
		}
		while(curB != NULL){
    		lenB++;
    		curB = curB->next;
		}
		curA = headA; curB = headB;
        //保证A是较长的链表
		if(lenB > lenA){
			swap(lenA,lenB);
			swap(curA,curB);
		}
        //将curA移动到和curB末尾对齐的位置
		int gap = lenA - lenB;
		while(gap--){
			curA = curA->next;
		}
        //比较curA和curB是否相同,不同则向后移动
		while(curA != NULL){
			if(curA == curB){
				return curA;
			}
			curA = curA->next;
			curB = curB->next;
		}
		return NULL;
    }
};

时间复杂度:O(m+n)  空间复杂度:O(1)


LeeCode 142.环形链表II

力扣题目链接 

思路:

定义快慢指针,快指针一次走两个结点,慢指针一次走一个结点,若快慢指针相遇,证明链表中存在环。此时定义两个指针,分别指向表头结点和快慢指针相遇的结点,遍历链表直至两指针相遇,相遇处即为环形入口的结点。

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
    	ListNode* fast = head;
    	ListNode* slow = head;
    	while(fast != NULL && fast->next != NULL){
    		slow = slow->next;
    		fast = fast->next->next;
    		//快慢指针相遇的结点即为环形入口的结点 
    		if(fast == slow){
    			ListNode* index1 = fast;
    			ListNode* index2 = head;
    			while(index1 != index2){
    				index1 = index1->next;
    				index2 = index2->next;
				}
				return index2;
			}
		}
        return NULL;
    }
};

  时间复杂度:O(n)     空间复杂度:O(1)  


总结

1.虚拟头结点的使用可以避免单独对涉及头结点的特殊情况进行讨论。

2.说实话,两两交换结点的题目,一堆指针互相交换,是真的很容易迷。虽然理解了每一步要干嘛,但不太懂为什么代码写成这样。o(╥﹏╥)o

3.后两道题一开始都没思路,但看完讲解之后理解了,能把代码顺下来。没写出来主要还是因为只停留在想的层面,没有动手画图解答。链表的题目画图对理解很重要!

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。