1.移除链表元素
题目链接/文章讲解/视频讲解:: 代码随想录
虚拟头结点:
代码:(虚拟头结点):这道题我以前也写过题解
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
// 虚拟头结点
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* cur = dummyHead;
while(cur->next != NULL){
if(cur->next->val == val){
ListNode* temp = cur->next;
cur->next = cur->next->next;
delete temp;
temp = nullptr;
}else{
cur = cur ->next;
}
}
return dummyHead->next;
}
};
思路:
可以一口气写个大概了,但是还是错了,我错在while循环里的判断语句没有用if
else,而是直接把cur = cur->next放到了了if后面,也就是每一次循环都这样一下。
这样做会操作空指针!(如下图所示)
头结点特殊处理
代码:(头结点特殊处理)
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
// 不使用虚拟头结点,分开讨论
while((head != NULL)&&(head->val == val)){
ListNode* temp = head;
head = head->next;
delete temp;
}
ListNode* cur = head;
while((cur !=NULL)&&(cur->next != NULL)){
if(cur->next->val == val){
ListNode* temp = cur->next;
cur->next = cur->next->next;
delete temp;
}else{
cur = cur->next;
}
}
return head;
}
};
思路:
新的bug已经出现,我怎能够停滞不前!这次问题出现在在处理一般结点时,没有在判断条件加上cur!=NULL,这里处理的时候,cur的初值不是我自己创建的肯定不是空指针的虚拟头结点了,而是头结点了,我一上来就cur->next,可能操作空指针了。而且这俩判断条件顺序还不能反!不然都会操作空指针。
还有一个低级错误,我直接cur->next==val了,离谱。
2.设计链表
题目链接/文章讲解/视频讲解:代码随想录
代码:这道题我以前也写过
class MyLinkedList {
public:
struct LinkNode{
int val;
LinkNode* next;
LinkNode(int val): val(val),next(NULL){
}
};
MyLinkedList() {
_size = 0;
_dummyhead = new LinkNode(0);
}
int get(int index) {
if((index < 0)||(index >= _size)){
return -1;
}
LinkNode* cur = _dummyhead->next;
while(index--){
cur = cur->next;
}
return cur->val;
}
void addAtHead(int val) {
LinkNode* newNode = new LinkNode(val);
newNode->next = _dummyhead->next;
_dummyhead->next =newNode;
_size++;
}
void addAtTail(int val) {
LinkNode* cur = _dummyhead;
while(cur->next !=NULL){
cur = cur->next;
}
LinkNode* newNode = new LinkNode(val);
cur->next = newNode;
_size++;
}
void addAtIndex(int index, int val) {
if(index > _size) return;
if(index < 0){
val = 0;
}
LinkNode* cur = _dummyhead; // 找第index-1个结点,不然无法对第index个结点操作
while(index--){
cur = cur->next;
}
LinkNode* newNode = new LinkNode(val);
newNode->next = cur->next;
cur->next = newNode;
_size++;
}
void deleteAtIndex(int index) {
if((index < 0)||(index >= _size)) return;
LinkNode* cur = _dummyhead; // 找第index-1个结点,不然无法对第index个结点操作
while(index--){
cur = cur->next;
}
LinkNode* temp = cur->next;
cur->next = cur->next->next;
delete temp;
_size--;
}
private:
int _size;
LinkNode* _dummyhead;
};
思路:
这次对应cur指针的初始取值就没什么错了。但是,又发现了新的错。老是少些_size的变化,还有判断条件我应该用或而不是与(根本就没有思考这个,就随随便便写上去了sos)
3.反转链表
题目链接/文章讲解/视频讲解: 代码随想录
双指针法:
代码:
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* cur = head;
ListNode* pre = NULL;
ListNode* temp = NULL;
while(cur != NULL){
temp = cur->next;
cur->next = pre;
pre = cur;
cur = temp;
}
return pre;
}
};
思路:
成功写出来了!翻转链表,就是把每两个结点间的指向翻转一下。为了实现这样的操作,用一个temp指针提前保存下一个要操作的结点即可。以及赋值顺序不能变,必须先pre=cur;如果先移动cur,我们刚刚翻转过的的结点就丢失了。
递归法:
代码:
class Solution {
public:
ListNode* reverse(ListNode* pre ,ListNode* cur){
if(cur == NULL) return pre;
ListNode* temp = cur->next;
cur->next = pre;
return reverse(cur,temp);
}
ListNode* reverseList(ListNode* head) {
return reverse(NULL,head);
}
};
思路:
其实只要懂了双指针,递归也好写。就是把每次更新遍历指针的操作放在递归中了。
但是这还是阻止不了我犯错,一个是递归出口错了。我写成了cur->next==NULL。老天,这样写,最后一个结点还没翻转就不管它了。。。还有return那里犯了个低级错误,调用函数就不用写返回类型了(我也不知道我为什么要这么写。。。)