203.移除链表元素
题意:删除链表中等于给定值 val 的所有节点。 示例 1: 输入:head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5] 示例 2: 输入:head = [], val = 1 输出:[] 示例 3: 输入:head = [7,7,7,7], val = 7 输出:[]
思路
- 虚拟头结点: 在开始时,创建一个新的虚拟头结点
dummyHead。这个节点不包含任何实际的数据,但它的next指针指向原始链表的头节点。使用虚拟头结点可以简化边界条件的处理,特别是当需要删除的节点是原始链表的头节点时。 - 初始化指针: 初始化一个指针
p,并将其指向虚拟头结点。这个指针将用于遍历链表。 - 遍历链表: 使用
p指针遍历链表。在每一步中,检查p的next节点的值是否等于val。
- 如果等于
val,则p的next节点需要被删除。为此,首先保存p->next节点的地址到一个临时指针temp。然后,更新p->next的值为p->next->next,这样就跳过了p->next节点,从而删除了它。最后,释放temp指针所指向的内存。 - 如果不等于
val,则将p指针移动到下一个节点。
- 更新头结点: 遍历完成后,将
head指针更新为dummyHead的next指针,因为dummyHead是虚拟头结点,所以真正的链表从dummyHead->next开始。 - 释放虚拟头结点的内存: 释放
dummyHead所占用的内存。 - 返回结果: 返回更新后的
head指针。
这种方法的时间复杂度为O(n),其中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(); // 设置一个虚拟头结点
dummyHead->next = head; // 将虚拟头结点指向head,这样方面后面做删除操作
ListNode* p = dummyHead;
while(p->next!=NULL){
if(p->next->val==val){
ListNode *temp=p->next;
p->next=p->next->next;
delete temp;
}
else p=p->next;
}
head = dummyHead->next;
delete dummyHead;
return head;
}
};
707.设计链表
在链表类中实现这些功能:
- get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
- addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
- addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
- addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
- deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
思路
- 节点定义:定义了一个内部结构体
LinkedNode,它包含一个整数值val和一个指向下一个节点的指针next。 - 链表属性:链表有一个虚拟头节点
dHead和一个整数size来存储链表的长度。 - 初始化:在构造函数中,初始化虚拟头节点和链表长度为0。
- get操作:从虚拟头节点的下一个节点开始,遍历链表直到达到指定的
index,然后返回该节点的值。 - addAtHead操作:创建一个新节点,并将其
next指针指向当前的头节点。然后更新虚拟头节点的next指针指向新节点。 - addAtTail操作:从虚拟头节点开始,遍历链表直到达到尾节点,然后在尾部添加新节点。
- addAtIndex操作:首先检查
index是否有效。然后从虚拟头节点开始,遍历链表直到达到指定的index,在该位置插入新节点。 - deleteAtIndex操作:首先检查
index是否有效。然后从虚拟头节点开始,遍历链表直到达到指定的index,删除该位置的节点。
这种设计使用了虚拟头节点来简化边界条件的处理,特别是当需要操作的节点是原始链表的头节点时。虚拟头节点不存储任何实际的数据,但它的next指针指向原始链表的头节点。
题解
class MyLinkedList {
public:
struct LinkedNode {
int val;
LinkedNode* next;
LinkedNode(int val):val(val), next(nullptr){}
};
MyLinkedList() {
dHead=new LinkedNode(0);
size=0;
}
int get(int index) {
if(index<0||index>(size-1)){
return -1;
}
LinkedNode *p=dHead->next;
for(int i=0;i<index;i++){
p=p->next;
}
return p->val;
}
void addAtHead(int val) {
LinkedNode *L=new LinkedNode(val);
L->next=dHead->next;
dHead->next=L;
size++;
}
void addAtTail(int val) {
LinkedNode *T=new LinkedNode(val);
LinkedNode *p=dHead;//dhead->next会出现空指针错误
while(p->next!=nullptr){
p=p->next;
}
p->next=T;
size++;
}
void addAtIndex(int index, int val) {
if(index>size)return;
if(index<0)index=0;//如果index小于0,则在头部插入节点
LinkedNode *I=new LinkedNode(val);
LinkedNode *p=dHead;
for(int i=0;i<index;i++){
p=p->next;
}
I->next=p->next;
p->next=I;
size++;
}
void deleteAtIndex(int index) {
if(index>(size-1)||index<0)return;
LinkedNode *p=dHead;
while(index--){
p=p->next;
}
LinkedNode *q=p->next;
p->next=p->next->next;
delete q;
size--;
}
private:
LinkedNode *dHead;
int size;
};
/**
* 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.反转链表
题意:反转一个单链表。 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL
思路
我使用迭代方法反转链表的解法。以下是该解法的简短思路:
- 初始化两个指针:
p指向当前要反转的节点,初始时指向head;q指向已经反转的部分的头节点,初始时为nullptr。 - 遍历链表:当
p不为nullptr时,继续执行以下操作:
- 先保存
p的下一个节点到temp,这样我们就不会在反转后丢失对链表的其余部分的引用。 - 更新
p的next指针,使其指向q,从而实现节点的反转。 - 移动
q到p的位置,然后移动p到temp的位置,为下一次迭代做准备。
- 返回结果:遍历完成后,
q指向新的头节点,因此返回q。
这种方法的时间复杂度是O(n),其中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* reverseList(ListNode* head) {
ListNode *q=NULL,*p=head;
while(p){
ListNode *temp=p->next;
p->next=q;
q=p;
p=temp;
}
return q;
}
};