LeetCode203 移除链表元素
题目链接:移除链表元素
思路
因为该链表没有头结点,和考研时学的还有点出入,不过只是在处理首元结点上有点差异,单独处理即可,思路为:①若head->val==val,则直接将head指针后移并释放掉原首元结点即可;②若工作指针p->next->val==val,则将p->next=p->next->next,然后将原p->next释放。注:之前DS上的代码基本都是伪代码,对于指针置空或者边界条件都没有很严格,导致自己在这上面也是翻了些错——俩while循环里面的指针一开始都忘记加不为空的条件导致执行错误。
扩展思路:可以像之前学的,给该链表加上一个头结点Lnodehead,这样该链表后续所有结点删除操作都一致,无需再单独讨论首元结点,最后返回Lnodehead->next即可。
代码
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
if (head == nullptr)
return nullptr;
while (head != nullptr && head->val == val) { //首元结点单独处理
ListNode* temp = head;
head = head->next;
delete temp;
}
ListNode* p = head;
while (p != nullptr && p->next != nullptr) {
if (p->next->val == val) {
ListNode* temp = p->next;
p->next = p->next->next;
delete temp;
} else {
p = p->next;
}
}
return head;
}
};
附随想录中带虚拟头结点代码
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* dummyHead = new ListNode(0); // 设置一个虚拟头结点
dummyHead->next = head; // 将虚拟头结点指向head,这样方便后面做删除操作
ListNode* cur = dummyHead;
while (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;
}
};
复杂度
时间复杂度 O(n)
空间复杂度O(1)
Leetcode707 设计链表
题目链接:设计链表
思路
本题较上题就采用了使用头结点的做法,并增加size字段以便于判断范围:①get,对于不在范围内index返回-1,在范围内便遍历到该处然后返回对应的值;②addAtHead,头插法,注意顺序防断链即可;③addAtTail,尾插法,一开始想减少时间耗费使用尾指针,但是头插按标号插入的情况尾指针不方便修改,于是改用直接遍历一遍链表,在末尾插入;④addAtIndex,按标号插入,遍历链表至index位置插入即可。实现头插和尾插时也可以直接调用该函数 ⑤deleteAtIndex,按标号删除,也是先查找到相应位置然后执行删除操作。
代码
class MyLinkedList {
public:
struct ListNode {
int val;
ListNode* next;
ListNode(int val) : val(val), next(nullptr) {}
};
MyLinkedList() {
Lnodehead = new ListNode(0);
size = 0;
}
int get(int index) {
if (index >= size || index < 0)
return -1;
ListNode* p = Lnodehead->next;
while (index--) {
p = p->next;
}
return p->val;
}
void addAtHead(int val) { //头插
ListNode* temp = new ListNode(val);
temp->next = Lnodehead->next; //注意顺序防止断链
Lnodehead->next = temp;
size++;
}
void addAtTail(int val) { //尾插
ListNode* temp = new ListNode(val);
ListNode* p = Lnodehead;
while (p->next != nullptr) {
p = p->next;
}
p->next = temp;
size++;
}
void addAtIndex(int index, int val) {
if (index <= size && index >= 0) {
ListNode* temp = new ListNode(val);
ListNode* p = Lnodehead;
while (index--) {
p = p->next;
}
temp->next = p->next;
p->next = temp;
size++;
}
}
void deleteAtIndex(int index) {
if (index < size && index >= 0) {
ListNode* p = Lnodehead;
while (index--) {
p = p->next;
}
ListNode* temp = p->next;
p->next = p->next->next;
delete temp;
size--;
}
}
private:
int size;
ListNode* Lnodehead;
};
复杂度
时间复杂度 get、addAtIndex、deleteAtIndex: O(index)
addAtHead:O(1)
addAtTail:O(len),其中len为链表长度
空间复杂度O(1)
Leetcode206 反转链表
题目链接:反转链表
思路
链表逆置,通过双指针可完成:设置工作指针p初始为head,p前置指针pre初始为Null。当p不为Null时循环,利用temp暂存p-next,防止断链,并将p->next=pre完成一个结点的逆置,最后更新pre和p。循环结束后pre即指向逆置后链表的头结点,返回。
代码
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* p=head; //工作指针
ListNode* pre=nullptr; //p前置
while(p!=nullptr){
ListNode* temp=p->next; //防断链
p->next=pre; //逆置
//更新指针
pre=p;
p=temp;
}
return pre;
}
};
复杂度
时间复杂度 O(n)
空间复杂度O(1)