目录
LeetCode 203. 移除链表元素
题目链接:LeetCode 203. 移除链表元素
思想:本题难点在于头结点的移除方式与其他节点不同。头结点的移除方式为:将一个临时节点等于目前的头结点,让指向头结点的指针指向下一个节点,然后删除新节点。其他节点的移除方式为:将一个临时节点指向将要移除的节点,将前一个节点指针指向移除元素的下一个节点,再将移除的节点删除就行。这里可以引用一个虚拟头结点的思想,即在原先的链表里面插入一个虚拟头结点,这样链表中所有节点的删除操作都是一样的了。
代码如下:
ListNode* removeElements(ListNode* head, int val) {
ListNode* virtualHead = new ListNode(0, head); // 虚拟头结点
ListNode* curNode = virtualHead; // 用来遍历链表的结点指针
while (curNode->next != NULL){
if (curNode->next->val == val){
ListNode* temp = curNode->next;
curNode->next = curNode->next->next;
delete temp;
}else{
curNode = curNode->next;
}
}
head = virtualHead->next;
delete virtualHead;
return head;
}
时间复杂度:O(n),空间复杂度:O(1)。
LeetCode 206. 反转链表
题目链接:LeetCode 206. 反转链表
思想:反转只需要更改两个结点之间的指针指向就行了,通俗地来讲就是把指针方向旋转180°。但更改了两个节点之间的指针之后,通常会发现丢失后续第三个结点的位置,就进行不了下一步操作了。所以需要前后三个节点进行反转操作。第一步将temp指向三个中的最后一个结点,第二步将cur节点的下一个结点指向pre,第三步pre等于cur,最后一步将cur节点等于temp。类似于下图?注意:cur前面应该有一个temp。
图出自代码随想录->链表->4.翻转链表里。
代码如下:
ListNode* reverseList(ListNode* head) {
ListNode* temp;
ListNode* curNode = head;
ListNode* preNode = NULL;
while (curNode != NULL){
temp = curNode->next;
curNode->next = preNode;
preNode = curNode;
curNode = temp;
}
return preNode; // 翻转过来就是pre头结点了
}
时间复杂度:O(n),空间复杂度:O(1)。
LeetCode 24. 两两交换链表中的节点
思想:这题跟上题有异曲同工之处,可以看作每次是两个结点的链表反转。所以交换的操作可以类似于上题的反转操作,但由于在进行每一对结点交换操作之后需要连接到下一对结点上,所以这里又需要一个结点来保存下一对结点的位置。第一步是将cur结点的下一个节点指向交换结点的第二个,第二步将第二个交换结点的下一个结点指向第一个交换结点,第三步将第一个交换结点的下一个结点指向下一对交换结点的第一个,最后将cur结点移动到这对交换结点的第二个。听起来可能有点绕。效果图如下?
图出自代码随想录->链表->5.两两交换链表中的节点里。
代码如下:
ListNode* swapPairs(ListNode* head) {
if (head == NULL || head->next == NULL){
return head;
} // 特殊情况
ListNode* virtualNode = new ListNode(0, head);
ListNode* curNode = virtualNode;
while (curNode->next != NULL && curNode->next->next != NULL){
ListNode* temp1 = curNode->next;
ListNode* temp2 = curNode->next->next->next;
curNode->next = curNode->next->next;
curNode->next->next = temp1;
temp1->next = temp2;
curNode = curNode->next->next;
}
return virtualNode->next;
}
时间复杂度:O(n),空间复杂度:O(1)。
总结
其实今天也做了另一题LeetCode 707. 设计链表。可我一直报错,应该是编译器在执行的时候,在循环的时候链表采取了cur=cur->next;类似操作的时候需要判断cur这个结点是否为空,不然是不会让你编译成功的。换言之,就是while循环的判断语句中需要加上while (cur != NULL)这一项;其次,新学到了虚拟头结点这个知识,通常在链表的增删改操作中运用会有奇效。查这一操作的话,可以不采用。