返回倒数第K个节点
![](https://img-blog.csdnimg.cn/direct/13fa09928e8148b6b98dc3e8b00b872c.png)
思路:创建快慢指针分别指向头节点,让快指针先走k步使快慢指针保持k个距离,走完在让快慢指针一起走,当快指针走到空,慢指针当前位置就是倒数第k个节点。
struct ListNode* fast = head,*slow = head; //快指针先走k步 让快慢指针保持k个距离 while(k--) { fast = fast->next; } //如果给的是无效的k,就要判断一下 if(fast) return NULL; //快慢指针一起走 while(fast) { fast = fast->next; slow = slow->next; } //将找到的倒数k节点的值返回 return slow->val;
链表的回文结构
![](https://img-blog.csdnimg.cn/direct/32678ec81c8446b5a4c517b8127f2089.png)
- 回文的概念:从中间切开俩边对称就是回文。
- 思路:找到中间节点,从中间节点开始后面逆置,头节点和中间节点依次往后判断是否相等,走到尾就是回文,不然就不是回文。
- 找中间节点的两种情况:奇数个数只有一个中间节点,偶数个数有俩个中间节点,返回第二个中间节点。
- 奇数个数比较时不要被表象迷惑最后一个数没数比,中间节点前一个数指向的就是最后一个要比较的数,所以是它自己和自己比。
/* struct ListNode { int val; struct ListNode *next; ListNode(int x) : val(x), next(NULL) {} };*/ //找中间节点 struct ListNode * middlenode(struct ListNode *head) { struct ListNode *fast = head,*slow = head; while(fast && fast->next) { fast = fast->next->next; slow = slow->next; } return slow; } //逆置 struct ListNode *reverseList(struct ListNode *head) { struct ListNode *cur = head; struct ListNode *newhead = NULL; while(cur) { struct ListNode *next = cur->next; cur->next = newhead; newhead = cur; cur = next; } return newhead; } class PalindromeList { public: bool chkPalindrome(ListNode* A) { struct ListNode *mid = middlenode(A); struct ListNode *rmid = reverseList(mid); while(A && rmid) //头节点或中间节点有一个为空就结束 { if(A->val != rmid->val) //判断A的值和rmid的值是否相等 不相等返回假 return false; A = A->next; rmid = rmid->next; } return true; } };
相交链表
![](https://img-blog.csdnimg.cn/direct/eaaf0d9b51e64ed79a0e94e090937c3b.png)
- 注: 因为单链表只能指向一个下一个地址所以相交不存在X型只能是Y型。
- 判断是否相交(判断尾指针,注意需要用地址判断),若相交找出第一个交点。
- 思路1:A链表的节点依次跟B链表所有节点比较,A某个节点跟B链某个节点相等,这个节点就是交点,时间复杂度O(N^2)。
- 思路2:先将A、B各链表走到尾节点判断地址是否相等,不相等即为不相交返回空,相等即为相交,再求出A、B链表长度,让长链表先走出差距步,在同时走第一个相等就是开始相交的位置,时间复杂度为O(N)。
![]()
O(3*N) /** * 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; //创建俩个变量保存俩个链表的长度,因为最后一个节点的NEXT为空进不去循环无法++少计算一个,所以初始 //化为1 int lenA = 1,lenB = 1; while(curA->next) //让A链表一直走,走到节点的NEXT指向空结束求出长度。 { curA = curA->next; ++lenA; } while(curB->next) //让B链表一直走,走到节点的NEXT指向空结束求出长度。 { curB = curB->next; ++lenB; } if(curA != curB) //此时A、B链表都走到最后如果不相等即不相交 返回NULL { return NULL; } //假设法 int gap = abs(lenA - lenB);//求出A和B的绝对值 struct ListNode *longList = headA,*shortList = headB;//假设A长、B短 if(lenB >lenA)//判断B如果比A长将B赋给长变量、A赋给短变量 { longList = headB; shortList = headA; } //长的先走差距步 while(gap--) { longList = longList->next; } //同时走,第一个相等就是交点 while(longList != shortList) { longList = longList->next; shortList = shortList->next; } return longList; }
随机链表的复制
/* 解题思路: 此题可以分三步进行: 1.拷贝链表的每一个节点,拷贝的节点先链接到被拷贝节点的后面
2.复制随机指针的链接:拷贝节点的随机指针指向被拷贝节点随机指针的下一个位置
3.拆解链表,把拷贝的链表从原链表中拆解出来
*/class Solution { public: Node* copyRandomList(Node* head) { // 1.拷贝链表,并插入到原节点的后面 Node* cur = head; while(cur) { Node* next = cur->next; Node* copy = (Node*)malloc(sizeof(Node)); copy->val = cur->val; // 插入 cur->next = copy; copy->next = next; // 迭代往下走 cur = next; } // 2.置拷贝节点的random cur = head; while(cur) { Node* copy = cur->next; if(cur->random != NULL) copy->random = cur->random->next; else copy->random = NULL; cur = copy->next; } // 3.解拷贝节点,链接拷贝节点 Node* copyHead = NULL, *copyTail = NULL; cur = head; while(cur) { Node* copy = cur->next; Node* next = copy->next; // copy解下来尾插 if(copyTail == NULL) { copyHead = copyTail = copy; } else { copyTail->next = copy; copyTail = copy; } cur->next = next; cur = next; } return copyHead; } };