最近事情比较多,在休息日补上这次刷题,坚持坚持坚持!!!
第一题24. 两两交换链表中的节点
注意current即当前操作的结点,要指向所有移动结点方向最前面的一个结点,因为单链表无法知道当前结点的上一个结点在哪,因此需要指向最前面
class Solution {
public:
ListNode* swapPairs(ListNode* head) {
ListNode* virhead=new ListNode(0);
virhead ->next=head;
ListNode* current;
current = virhead;
//必须按照这个顺序否则后部可能出现空指针
while (current->next != NULL && current->next->next != NULL) {
ListNode* temp1;
ListNode* temp2;
temp1 = current->next;
temp2 = current->next->next->next;
//红色
current->next = current->next->next;
//蓝色
current->next->next = temp1;
//黄色
temp1->next = temp2;
current=current->next->next;
}
return virhead->next;
}
};
第二题19.删除链表的倒数第N个节点
这里的重点是找到倒数第N个结点在哪里,思路如下:
- 分别定义一个快慢指针,快指针先移动n步
- 快慢指针同步移动,直到快指针到达NULL,此时慢指针指向需要被删除的结点
但是,应该指向被删除结点的前一个结点,因此,需要更改上述:
- 方法一:快指针先移动n+1步
- 方法二:快慢指针同步移动,直到快指针的next到达NULL
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode* fast;
ListNode* slow;
ListNode* virhead=new ListNode(0);
virhead->next = head;
fast = virhead;
slow = virhead;
for (int i = 0; i < n+1; i++) {
fast = fast->next;
}
while (fast != NULL) {
fast = fast->next;
slow = slow->next;
}
ListNode* temp;
temp = slow->next;
slow->next = slow->next->next;
delete(temp);
return virhead->next;
}
};
第三题 面试题 02.07. 链表相交
本题的意思是:两个链表末端对齐后,找到相交的部分
如果是数组,可以从末尾往前逐个比较,找到相交的部分;但是单链表无法直接找到某个结点的前一个结点,因此只能从前往后比较,所以需要手动将两个链表末端对齐(长链表的头结点移动【长链表-短链表】个距离)
这个题有一个比较难理解的地方是:相交并不是值相等,是结点相等,与值无关,因此在判断是不是相等时应该使用"if(cmpA==cmpB)"而不是"if(cmpA.val==cmpB.val)",这一点可以在给的实例中看出(见下):如果是值相等,那么应该“1”也算作相交,但本题并未判为相交,因此应该是结点相等
class Solution {
public:
ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) {
//获取链表a长度
ListNode* current;
current = headA;
int countA=0;
while (current != NULL) {
current = current->next;
countA++;
}
//获取链表b长度
current = headB;
int countB = 0;
while (current != NULL) {
current = current->next;
countB++;
}
//差值
int cha = abs(countA - countB);
//移动链表至末尾相同
if (countA > countB) {
for (int i = 0; i < cha; i++) {
headA = headA->next;
}
}
if (countB > countA) {
for (int i = 0; i < cha; i++) {
headB = headB->next;
}
}
ListNode* cmpA = new ListNode(0);
ListNode* cmpB = new ListNode(0);
ListNode* jiao = new ListNode(0);
cmpA = headA;
cmpB = headB;
while (cmpA!=NULL) {
//此处并不是if (cmpA->val == cmpB->val)
//因为不是值相同,是节点相同
if (cmpA== cmpB) {
jiao = cmpA;
return jiao;
}
cmpA = cmpA->next;
cmpB = cmpB->next;
}
return NULL;
}
};
第四题142.环形链表II
该题主要分为两个步骤:
- 判断这个链表是否有环:设置一个快慢指针,开始时指向头结点,快指针一次走两步,慢指针一次走一步,如果有环则一定会相遇,没有环则一定不会相遇
- 找到链表开始入环的第一个结点:
由此说明,x等于绕了几次环之后加上z的和,因此可以定义两个指针index1,index2,分别指向头结点和相遇点,以相同的速度前进,当走到相同的结点时说明此处是环形入口处
class Solution {
public:
ListNode* detectCycle(ListNode* head) {
//判断是否有环
ListNode* fast=new ListNode(0);
ListNode* slow = new ListNode(0);
//头结点
ListNode* index1 = new ListNode(0);
//相遇点
ListNode* index2 = new ListNode(0);
fast = head;
slow = head;
index1 = head;
int pan=0;
//此处是为了防止空指针报错
while (fast!=NULL&&fast->next!= NULL&&fast->next->next!=NULL) {
slow = slow->next;
fast = fast->next->next;
//相遇
if (slow == fast) {
index2 = slow;
pan = 1;
break;
}
}
//没有环
if (pan==0) {
return NULL;
}
//找到环的入口
while (index1 != index2) {
index1 = index1->next;
index2 = index2->next;
}
return index1;
}
};
总结:感觉环形指针的思想还是很妙的!!