24 两两交换链表中的节点
题目链接
状态:指针换来换去头麻了
文档:programmercarl.com
思路:
实现中的问题:
循环的终止条件没弄明白,看了文档后算是自己理解了点。如果链表的元素个数是奇数:比如只有下标0,那么就是cur->next->next != NULL。如果链表的元素是偶数:比如没有元素,那么就是cur->next != NULL。
并且,两个的位置不能反,若先判断cur->next->next != nullptr的话,如果出现cur->next == nullptr,那上面这个语句就会出现空指针报错。这两个终止条件意思是既要满足奇数的也要满足偶数的。
并且一定要同时满足这两个条件。否则可能会出现空指针异常。就像节点3,要保护节点3是一个有效值,也就是cur->next->next->next是一个有效值。
代码:
/**
* 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* swapPairs(ListNode* head) {
//指针要指向要交换的两个元素之前的位置
//决定一下终止条件 奇数:cur->next->next == NULL
//偶数:cur->next == NULL
//因为指针指向会变,所以要先保存一下节点1、节点3的值
//设置虚拟节点
ListNode* dummy_node = new ListNode(0);
dummy_node->next = head; //设置虚拟头节点
//将临时指针指向虚拟头节点,这样才能控制要交换的那两个节点
ListNode* cur = dummy_node;
//设置临时节点存储断链的节点
ListNode* temp1; //存储节点1的位置
ListNode* temp2; //存储节点3的位置
while(cur->next != nullptr && cur->next->next != nullptr)
{
temp1 = cur->next;
temp2 = cur->next->next->next;
cur->next = cur->next->next;
cur->next->next = temp1;
temp1->next = temp2;
//cur向后移动两个
cur = cur->next->next;
}
//返回头节点
return dummy_node->next;
}
};
总结: 首先要保护的就是前链断掉的节点,其次再看哪个节点前后都断了,就保护它。
19 删除链表的倒数第N个节点
题目链接
状态:磕磕绊绊
文档:programmercarl.com
思路:
既然想删除节点,必不可少的就是遍历节点,创建一个遍历指针cur。
要注意的是这里的第n个,n是从1开始并不是从0开始的。
因为是倒数,所以我需要先计算出来链表的元素个数,这样才知道倒数第n个到底是正数的第几个元素。
注意:
delete cur;
用完指针一定要置空,不然变成野指针会很危险。
cur = NULL;
代码:
/**
* 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(0);
dummy_Head->next = head;
//临时保存cur指向的目标节点的前一个节点
ListNode* temp;
//创建一个临时指针,遍历元素
ListNode* cur = dummy_Head;
//计算链表元素个数
int size = 0;
while(cur->next != NULL)
{
size++;
cur = cur->next;
}
cout<<"元素个数为:"<<size<<endl;
cur = dummy_Head;
for(int i = 0;i<=size-n;i++)
{
temp = cur;
cur = cur->next;
}
//删除节点
temp->next = cur->next;
delete cur;
cur = NULL;
return dummy_Head->next;
}
};
面试题 02.07. 链表相交
题目链接
状态:很头疼 没太弄懂
文档:programmercarl.com
疑点:
在这个示例中,我很疑惑为什么相交的点不是1,而是8.所以我去测试用例中测试了一下。
第一种 交点是8
第二种,交点是1
两者结果的不同 取决于 skipA和skipB的值有所变动。
所以在实现的时候就正常实现,不用管那么多了。
思路:
要注意的一点是,这里的相同指的是指针相同,而不是元素的数值相同。指针相同的意思就是内存地址是相同的,我在看了很多博客之后,推荐
推荐阅读
用双指针 pA 、pB 循环两个链表,链表 A 循环结束就循环链表 B,链表 B 循环结束就循环链表 A;当 pA == pB 时就是交点,因为两个指针移动的步数一样;
代码:
/**
* 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) {
if(headA == NULL || headB == NULL) return NULL;
ListNode* pA = headA;
ListNode* pB = headB;
while(pA!=pB)
{
//pA不为空的时候指向下一个 为空的时候指向b的头节点
pA = pA == NULL?headB:pA->next;
pB = pB == NULL?headA:pB->next;
}
return pA;
}
};
142 环形链表II
题目链接
状态:没做出来
文档:programmercarl.com
看完文档后的理解:
Q:为什么会想起使用双指针呢?A:因为这道题在数学中实际上是同向相遇问题。
可以用双指针来判断到底有没有环。如果没有环的话,快慢指针永远都不会相遇;如果有环的话,快慢指针会相遇的。
Q:那什么情况下才会相遇?A:快指针每次走2个节点,而慢指针每次走1个节点,这样快指针比慢指针每次多走一个节点,那么快慢指针终究会遇上的。如果快指针每次比慢指针走多走2个节点,那么可能就会跳过慢指针从而无法相遇。
Q:为什么慢指针进入环的第一圈就被快指针给遇到了呢?
A:看图解
整体思路如下:
代码:
/**
* 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* fast = head;
ListNode* slow = head;
//因为快指针一次走两个节点,所以要判断他自己和下一个节点是否为空
while(fast !=NULL && fast->next!=NULL)
{
fast = fast->next->next;
slow = slow->next;
//相遇了,找到了环(在环的某处相遇了)
if(fast == slow)
{
ListNode* index1 = fast; //记录相遇节点
ListNode* index2 = head; //记录头节点
//在相遇前 不停往前走 寻找入口
//因为是共享一个节点 所以不应该说值相等 该说指针相等
while(index1 != index2)
{
//head到入口的距离 = 相遇点到入口的距离
index1 = index1->next;
index2 = index2->next;
}
//返回环的入口
return index1;
}
}
return NULL;
}
};
总结:数学逻辑性真的很重要呜呜呜