链表
203.移除链表元素
普通方法:需要分头节点和非头节点,需要用一个cur指针来遍历,因为要返回头节点,所以不能用head来遍历,注意C++需要手动清除内存
/**
* 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;
}
};
虚拟头节点法:加一个虚拟头节点,就可以统一以上两段代码,注意最后返回的是head = dummyHead->next,先保存head,再删dummyHead,再返回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) {
ListNode* dummyHead = new ListNode(0, head);//设置一个虚拟头节点
//dummyHead->next = head;
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;
}
}
head = dummyHead->next;
delete dummyHead;
return head;
}
};//duotingl
707.设计链表
index范围:0~size-1。此处设置了一个虚拟头节点dummyHead,如果cur从dummpyHead开始遍历,那么最后cur指向index-1节点,如果cur从dummyHead->next遍历,那么cur最后指向index节点。注意边界处理问题,如删除的时候不能删除size节点,但是插入可以。
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 > (_size - 1) || index < 0){
return -1;
}
LinkedNode *cur = _dummyHead -> next;
while(index--){
cur = cur -> next;
}
//此时cur指向index节点
return cur -> val;
}
void addAtHead(int val) {
LinkedNode* newNode = new LinkedNode(val);
newNode -> next = _dummyHead -> next;
_dummyHead -> next = newNode;
_size++;
}
void addAtTail(int val) {
LinkedNode* newNode = new LinkedNode(val);
LinkedNode* cur = _dummyHead;
while(cur->next != nullptr){
cur = cur -> next;
}
cur -> next = newNode;
_size++;
}
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;
}
//此时cur指向index-1节点
newNode -> next = cur -> next;
cur -> next = newNode;
_size++;
}
void deleteAtIndex(int index) {
if(index < 0 || index > (_size - 1)){
return;
}
LinkedNode* cur = _dummyHead;
while(index--){
cur = cur -> next;
}
//此时cur指向index-1节点
LinkedNode* tmp = cur -> next;
cur -> next = cur -> next ->next;
delete tmp;
//delete命令指示释放了tmp指针原本所指的那部分内存,
//被delete后的指针tmp的值(地址)并非就是NULL,而是随机值。也就是被delete后,
//如果不再加上一句tmp=nullptr,tmp会成为乱指的野指针
//如果之后的程序不小心使用了tmp,会指向难以预想的内存空间
tmp = nullptr;
_size--;
}
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);
*/
206.反转链表
双指针解法:
/**
* 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){
ListNode* tmp = cur->next;
cur->next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
};
递归解法一:
/**
* 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* pre, ListNode* cur){
if(cur==NULL) return pre;
ListNode* tmp = cur->next;
cur->next = pre;
return reverse(cur, tmp);
}
ListNode* reverseList(ListNode* head) {
return reverse(NULL, head);
}
};
递归解法二:
前两个解法都是从前往后进行两两反转,此解法是从后往前进行两两反转
head == NULL || head->next == NULL是特殊情况的判断。同时head->next==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* reverseList(ListNode* head) {
if(head == NULL || head->next == NULL){
return head;
}
ListNode* last = reverseList(head->next);
head->next->next = head;
head->next = NULL;
return last;
}
};
24.两两交换链表中的节点
画图理解
注意事项:最后别忘了cur = cur->next->next
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D6YAQSZq-1687509375200)(C:\Users\1\AppData\Roaming\Typora\typora-user-images\image-20230612141957125.png)]
/**
* 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) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* cur = dummyHead;
while(cur->next != nullptr && cur->next->next != nullptr){
ListNode* tmp = cur->next;
ListNode* tmp1 = cur->next->next->next;
cur->next = cur->next->next;//步骤一
cur->next->next = tmp;//步骤二
cur->next->next->next = tmp1;//步骤三
cur = cur->next->next;
}
return dummyHead->next;
}
};
19.删除链表的倒数第n个节点
设置快慢指针,先让快指针移动n+1步,然后快慢指针再同时移动,这样快指针永远比慢指针在前面n+1步,当快指针到NULL的时候,慢指针就在倒数第n+1个位置,此处删除slow后一个节点即可。设置一个虚拟头节点,可以解决删除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* removeNthFromEnd(ListNode* head, int n) {
ListNode* dummyHead = new ListNode(0);
dummyHead->next = head;
ListNode* slow = dummyHead;
ListNode* fast = dummyHead;
/*while(n-- && fast != NULL){
fast = fast->next;
}
fast = fast->next;*/
for(int i = 0; i <= n; i++){
fast = fast->next;
}
while(fast != NULL){
slow = slow->next;
fast = fast->next;
}
ListNode* tmp = slow->next;
slow->next = tmp->next;
delete tmp;
tmp = NULL;
return dummyHead->next;
}
};