24. 两两交换链表中的节点
解析:
基础题,主要是要把握边界条件:由题可得,交换的节点两两一组,每交换完成一对,问题规模减2,也就是只剩一个或不剩节点时交换便结束。
在这里,我们引入一个虚拟头节点,这样所有的交换操作便得到统一。
每一对节点交换一次,不开辟额外空间,因此时间复杂度O(n),空间复杂度O(1)。
-
class
Solution {
-
public:
-
ListNode* swapPairs(ListNode* head) {
-
ListNode* dummy_head =
new
ListNode(
-1, head);
//虚拟头节点
-
if(head ==
nullptr || head->next ==
nullptr)
return head;
//边界条件先判断
-
ListNode* cur2 = head->next;
-
ListNode* cur1 = head;
-
ListNode* pre = dummy_head;
//两个需要交换的节点,及前节点,共三个节点
-
while(cur1 && cur2){
-
cur1->next = cur2->next;
-
cur2->next = cur1;
-
pre->next = cur2;
-
-
pre = cur1;
-
if(cur1->next && cur1->next->next){
//若只剩1个或不剩 则退出交换
-
cur2 = cur1->next->next;
-
cur1 = cur1->next;
-
}
-
else {
-
break;
-
}
-
}
-
head = dummy_head->next;
//头节点还原
-
delete dummy_head;
-
return head;
-
}
-
};
19.删除链表的倒数第N个节点
解析:
本题以普通办法处理的话就是先遍历一遍,确定链表长度,再遍历一遍,实施删除。虽然不会到O(n^2)的复杂度,仍为线性,但是连续遍历两遍不免让人觉得不快。
因此此类问题,同样可以借鉴双指针法,一前一后不回溯的遍历链表,让前后指针距离保持 n 的距离,那么当后指针到达链表尾的时候,我们自然而然可以靠前指针确定删除位置,且该算法只需一遍遍历。
-
/**
-
* Definition for singly-linked list.
-
* struct ListNode {
-
* int val;
-
* ListNode *next;
-
* ListNode() : val(0), next(nullptr) {}
-
* ListNode(int x) : val(x), next(nullptr) {}
-
* ListNode(int x, ListNode *next) : val(x), next(next) {}
-
* };
-
*/
-
class
Solution {
-
public:
-
ListNode* removeNthFromEnd(ListNode* head, int n) {
-
ListNode* dummy_head =
new
ListNode(
-1,head);
-
ListNode* p = dummy_head;
-
ListNode* q = dummy_head;
-
int kick_off =
0;
-
while(kick_off < n && p->next){
//先让p指针先行,确定q指针何时行动
-
p = p->next;
-
kick_off++;
-
}
-
while(p->next){
//同步行动,直至p指针到最后一个节点,q指针离p n 个位置远
-
p = p->next;
-
q = q->next;
-
}
-
ListNode *tmp = q->next;
-
q->next = q->next->next;
//实施删除
-
-
if(dummy_head->next){
//判断一下是否链表就一个节点,且已被删除
-
head = dummy_head->next;
-
}
-
else{
-
head =
nullptr;
-
}
-
delete tmp;
// 回收要删除的节点
-
delete dummy_head;
//回收虚拟头
-
return head;
-
}
-
};
160.链表相交
解析:
这道题需要巧妙利用到一个思维,也就是链表尾对齐的思维。
如图:若两个链表有相交点,则该交点后的节点均为同一个节点,也就是它们是尾部相等的。所以如果我们能找到长表较之于短表表头的中间位置(等长的位置),然后顺序同步一对一对节点的比较是否相等,便能找到第一个相同的节点,且时间复杂度能控制在O(m+n)。
-
/**
-
* 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) {
-
ListNode* qq = headA;
-
int lenA =
1;
-
int lenB =
1;
-
ListNode* pp = headB;
-
while(qq->next){
//计算A的长度
-
qq = qq->next;
-
lenA++;
-
}
-
while(pp->next){
//计算B的长度
-
pp = pp->next;
-
lenB++;
-
}
-
ListNode* q = headA;
-
ListNode* p = headB;
-
if(lenA < lenB){
// 让q指向较长的链表的表头
-
int tmp = lenA;
-
ListNode* _tmp = q;
-
lenA = lenB;
-
lenB = tmp;
-
q = p;
-
p = _tmp;
-
}
-
int offset = lenA - lenB;
-
while(offset >
0 ){
//想象两个不等长的链表,由末尾对齐,将较长的链表的指针遍历到与较短的链表表头节点对齐
-
q = q->next;
-
offset--;
-
}
-
while(q != p && q){
//开始判等
-
q = q->next;
-
p = p->next;
-
}
-
return q;
-
}
-
};
142.环形链表II
解析:
该题涉及到一个数学推理,详情见卡哥:代码随想录
-
/**
-
* 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* p = head;
-
ListNode* q = head;
-
while( q && q->next){
-
p = p->next;
-
q = q->next->next;
-
if(p == q){
-
ListNode* pp = head;
-
ListNode* qq = q;
-
while(pp != qq){
-
pp = pp->next;
-
qq = qq->next;
-
}
-
return qq;
-
}
-
}
-
return
NULL;
-
}
-
};
转载:https://blog.csdn.net/sunnanhunan/article/details/128506857
查看评论