题目1:203 移除链表元素
题目链接:203 移除链表
题意
删除链表中所有满足Node.val==val的节点 返回新的头节点
注意使用cur临时指针,遍历链表,这样才可以最终返回head,不可以拿着head去遍历,否则,头节点会改变,无法返回整个链表
分类讨论
代码
/*** 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* removeElements(ListNode* head, int val) {//删除头节点while(head!=NULL && head->val==val){ListNode *tmp = head;//定义一个节点变量,用于释放内存head = head->next;delete tmp;//手动释放内存}//删除非头节点 (遍历所有节点)ListNode *cur = head;while(cur!=NULL && cur->next!=NULL){if(cur->next->val==val){ListNode *tmp = cur->next;//定义一个节点变量,用于释放内存cur->next = cur->next->next;delete tmp;//手动释放内存}else{cur = cur->next;} }return head;}
};
- 时间复杂度: O(n)
- 空间复杂度: O(1)
虚拟头节点
本题使用虚拟头节点方法 更优,这样不用分类讨论,可以统一操作
代码
/*** 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* removeElements(ListNode* head, int val) {//定义虚拟头节点ListNode *dummyhead = new ListNode(0);dummyhead->next = head;//定义临时指针cur,遍历链表ListNode *cur = dummyhead;//遍历所有的链表节点while(cur!=NULL && cur->next!=NULL){if(cur->next->val==val){ListNode *tmp = cur->next;//定义节点变量,用于释放内存cur->next = cur->next->next;delete tmp; //手动释放内存}else{cur = cur->next;}}return dummyhead->next;//注意返回的dummyhead一定是新链表的头节点}
};
- 时间复杂度: O(n)
- 空间复杂度: O(1)
题目2:707 设计链表
题目链接:707 设计链表
题意
链表实现如下功能:
①初始化节点
②获取链表的某个节点值 (index从0开始,head的index为0)
③在头节点前面插入一个节点
④在尾节点后面插入一个节点
⑤在第n个节点处插入一个节点
⑥删除第n个节点
代码
①初始化节点
//定义链表节点结构体struct LinkedNode {int val;LinkedNode* next;LinkedNode(int val):val(val),next(nullptr){} //没有分号};//初始化链表MyLinkedList() {dummyhead = new LinkedNode(0);size_ = 0; }
②获取链表的某个节点值 (index从0开始,head的index为0)
法1:cur指向dummyhead
代码1
int get(int index) {if(index<0 || index>(size_-1)) return -1;LinkedNode* cur = dummyhead;while(index){cur = cur->next;index--;}return cur->next->val; }
法2:cur指向dummyhead->next
代码2
int get(int index) {if(index<0 || index>(size_-1)) return -1;LinkedNode* cur = dummyhead->next;while(index){cur = cur->next;index--;}return cur->val; }
③在头节点前面插入一个节点
注意插入的节点顺序,这非常关键,这也是“坑”
代码
void addAtHead(int val) {LinkedNode* newnode = new LinkedNode(val);newnode->next = dummyhead->next;dummyhead->next = newnode;size_ ++;//注意添加了元素,要在原链表的基础上加1}
④在尾节点后面插入一个节点
注意while循环的条件是cur->next!=NULL 不能是size_
代码
void addAtTail(int val) {LinkedNode* cur = dummyhead;LinkedNode* newnode = new LinkedNode(val);while(cur->next!=nullptr){cur = cur->next;}cur->next = newnode;size_++;//添加了元素,链表大小加1}
!!!错误代码(如果使用size_做循环操作,那么意味着表示链表大小的量size_会发生变化,不能拿代表真实的链表大小了)
void addAtTail(int val) {LinkedNode* cur = dummyhead;LinkedNode* newnode = new LinkedNode(val);while(size_){cur = cur->next;size_--;}cur->next = newnode;size_++;//添加了元素,链表大小加1}
如果想要使用这个量用于while循环的条件判定,可以将size_赋值给一个新变量n,代码如下,这时,代码就是正确的了
void addAtTail(int val) {int n = size_;LinkedNode* cur = dummyhead;LinkedNode* newnode = new LinkedNode(val);while(n){cur = cur->next;n--;}cur->next = newnode;size_++;//添加了元素,链表大小加1}
⑤在第n个节点处插入一个节点
注意“坑” :即顺序
在第n个节点处插入一个节点,因此一定要知道第n-1个节点,所以cur=dummyhead
代码
void addAtIndex(int index, int val) {if(index>size_) return;if(index<0) index = 0;LinkedNode* newnode = new LinkedNode(val);LinkedNode* cur = dummyhead;while(index){cur = cur->next;index--;}newnode->next = cur->next;cur->next = newnode;size_++;//新加入了节点,链表大小要加1}
⑥删除第n个节点
删除第n个节点,一定要知道第n-1个节点,因此,cur=dummyhead
代码
void deleteAtIndex(int index) {if(index>(size_-1)||index<0) return;LinkedNode* cur = dummyhead;while(index){cur = cur->next;index--;}//注意释放内存LinkedNode* tmp = cur->next;cur->next = cur->next->next;delete tmp;tmp = nullptr;size_--;//删除了一个元素,链表大小减1}
整体代码
class MyLinkedList {
public:
//定义链表节点结构体struct LinkedNode {int val;LinkedNode* next;LinkedNode(int val):val(val),next(nullptr){} //没有分号};//初始化链表MyLinkedList() {dummyhead = new LinkedNode(0);size_ = 0; }int get(int index) {if(index<0 || index>(size_-1)) return -1;LinkedNode* cur = dummyhead;while(index){cur = cur->next;index--;}return cur->next->val; }void addAtHead(int val) {LinkedNode* newnode = new LinkedNode(val);newnode->next = dummyhead->next;dummyhead->next = newnode;size_ ++;//注意添加了元素,要在原链表的基础上加1}void addAtTail(int val) {LinkedNode* cur = dummyhead;LinkedNode* newnode = new LinkedNode(val);while(cur->next!=nullptr){cur = cur->next;}cur->next = newnode;size_++;//添加了元素,链表大小加1}void addAtIndex(int index, int val) {if(index>size_) return;if(index<0) index = 0;LinkedNode* newnode = new LinkedNode(val);LinkedNode* cur = dummyhead;while(index){cur = cur->next;index--;}newnode->next = cur->next;cur->next = newnode;size_++;//新加入了节点,链表大小要加1}void deleteAtIndex(int index) {if(index>(size_-1)||index<0) return;LinkedNode* cur = dummyhead;while(index){cur = cur->next;index--;}//注意释放内存LinkedNode* tmp = cur->next;cur->next = cur->next->next;delete tmp;tmp = nullptr;size_--;//删除了一个元素,链表大小减1}void printLinkedList() {LinkedNode* cur = dummyhead;while(cur->next!=nullptr){cout<<cur->next->val<<" ";cur = cur->next;}cout<<endl; }
private:int size_;LinkedNode* dummyhead;
};/*** Your MyLinkedList object will be instantiated and called as such:* MyLinkedList* obj = new MyLinkedList();* int param_1 = obj->get(index);* obj->addAtHead(val);* obj->addAtTail(val);* obj->addAtIndex(index,val);* obj->deleteAtIndex(index);*/// 打印链表
- 时间复杂度: 涉及
index
的相关操作为 O(index), 其余为 O(1) - 空间复杂度: O(n) 其中 n 为链表的长度。需要为每个节点分配内存空间来存储节点的值和下一个节点的指针,并且还需要一个额外的虚拟头节点指向链表的头部。
题目3:206 反转链表(面试高频)
题目链接:206 反转链表
题意
根据链表的头节点head 返回反转后的链表
双指针
代码
/*** 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* reverseList(ListNode* head) {ListNode* pre = NULL;ListNode* cur = head;while(cur!=NULL){ListNode* temp = cur->next;cur->next = pre;//pre,cur向后移动一位pre = cur;cur = temp;}return pre;}
};
- 时间复杂度: O(n)
- 空间复杂度: O(1)
递归
代码
/*** 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* reverse(ListNode* cur, ListNode* pre){//终止条件if(cur==NULL) return pre;//单层递归逻辑ListNode* temp = cur->next;cur->next = pre;return reverse(temp,cur);}ListNode* reverseList(ListNode* head) {return reverse(head,NULL);}
};
- 时间复杂度: O(n), 要递归处理链表的每个节点
- 空间复杂度: O(n), 递归调用了 n 层栈空间