链表
203.移除链表元素
在链表操作中,有两种方式进行修改
- 直接使用原来的链表来进行删除操作
本操作在表头和其他部位的操作需要特判,不方便
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
while(head!=NULL&&head->val == val){
ListNode* p = head;
head = head->next;
delete p;
}
ListNode* p = head;
// p!=NULL很重要!
while(p!=NULL && p->next!=NULL){
ListNode* q = p->next;
if(q->val == val){
p->next = q->next;
delete q;
}
else p = p->next;
}
return head;
}
};
- 设置一个虚拟头结点在进行删除操作
本操作将对于表头和其他节点的操作统一化
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode *p = new ListNode(0);
// 添加一个前置虚拟节点
p->next = head;
auto q = p;
while(p != NULL && p->next != NULL){
auto m = p->next;
if(m->val == val){
p->next = m->next;
delete m;
}
else p = p->next;
}
return q->next;
}
};
707.设计链表
这题的关键就是要构造一个虚拟头节点,以统一操作
class MyLinkedList {
public:
struct LinkNode{
int val;
LinkNode* next;
LinkNode(int val):val(val),next(NULL){}
};
LinkNode* dummyhead = NULL;
int size;
MyLinkedList() {
dummyhead = new LinkNode(0);
size = 0;
}
int get(int index) {
if(index > size - 1 || index < 0) return -1;
LinkNode* p = dummyhead->next;
for(int i = 0; i< index; i++){
p = p->next;
}
return p->val;
}
void addAtHead(int val) {
LinkNode* p = new LinkNode(val);
p->next = dummyhead->next;
dummyhead->next = p;
size++;
}
void addAtTail(int val) {
LinkNode *p = dummyhead;
while(p->next!= NULL) p = p->next;
LinkNode *q = new LinkNode(val);
p->next = q;
size++;
}
void addAtIndex(int index, int val) {
if(index > size) return;
if(index < 0) index = 0;
LinkNode* p = dummyhead;
LinkNode* q = new LinkNode(val);
while(index--){
p = p->next;
}
q->next = p->next;
p->next = q;
size++;
}
void deleteAtIndex(int index) {
if(index >= size || index < 0) return;
LinkNode* p = dummyhead;
while(index--){
p = p->next;
}
auto q= p->next;
p->next = q->next;
delete q;
size--;
}
};
206.反转链表
直接遍历链表,然后创建一个虚拟头节点dummy,依次把遍历来的节点的对应值进行头插法,这样就实现了反转。
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* p = head;
ListNode *dummy = new ListNode(0);
while(p != NULL){
ListNode *q = new ListNode(p->val);
q->next = dummy->next;
dummy->next = q;
p = p->next;
}
return dummy->next;
}
};
原地逆置,只需要使用两个指针,逐个逐个逆转每个节点下一个指针的方向(指向前一个),这个操作需要记录前一个节点,因为当前节点cur的下一个指针应该是指向上一个节点的。
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode *cur = head;
ListNode *pre = nullptr;
while(cur!=NULL){
ListNode* t = cur->next;
cur->next = pre;
pre = cur;
cur = t;
}
return pre;
}
};
递归
递归最开始是结束或剪枝的条件
然后再把原地逆置的逻辑套入即可,这里的递归实际上是进行了一个类似前序遍历的操作。
因为需要返回新链表的头节点,所以函数需要返回指针。
class Solution {
public:
ListNode* reverse(ListNode* pre,ListNode* cur){
// 当cur为null的时候,pre正好是指向原最后一个节点的。
if(cur == NULL) return pre;
ListNode* t = cur->next;
cur->next = pre;
// 把pre和cur更改的操作变成传入递归的参数
return reverse(cur,t);
}
ListNode* reverseList(ListNode* head) {
return reverse(NULL,head);
}
};