203. 移除链表元素
心得
- 想到虚拟头结点,但是实际写的时候对于指针、结构、链表的的基本操作不熟悉,用错如指向结构的指针(*pt).val (*pt).next 和pt→val 和pt→next等同
- 需要注意符合单链表结构的,从当前和next考虑,而不是prev和cur考虑(名称可能会议歧义)
题解
- 如果采用正常方法就是区分头结点和其他,对于头结点直接后移即可,但要注意连续出现的情况,所以针对头结点处理是循环方式,其次使用当前结点和next符合题意的单链表,而不是用prev,虽然做的事情一样,但是名称会误导
- 虚拟头结点注意返回值,在正常办法情况下head已经替换掉了,直接返回即可,但是统一处理的虚拟头结点中的head其实已经被next接管替换,所以需要重新替换,同时注意释放内存
/**
* 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
ListNode* cur = dummyHead
while (cur->next != nullptr){
if (cur->next->val == val){
ListNode* temp = cur->next
cur->next = cur->next->next
delete temp
}
else {
cur = cur->next
}
}
head = dummyHead->next
delete dummyHead
return head
}
}
707. 设计链表
心得
- 链表构造不熟悉,结构需要自己处理,同时规范的类相关要求不熟悉,比如命名规范等
- 尤其看到函数多,有畏难情绪,其实mid难度函数这么多一般难度其实会降下来
- 题目的规范性确实是个类的良好学习样例
题解
- 为方便统一操作,构造虚拟头结点,对于输入size需要判断异常,再进行即可,对于特定位置需要先新建,然后加遍历到达的位置即可
- 尤其需要注意前后赋值问题和循环退出条件
- 注意需要遍历的位置基本都是dummyHead而不是对应next,其实就是判断0索引存不存在的情况
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 || index < 0) {
return -1
}
LinkedNode* cur = _dummyHead->next
while (index--){
cur = cur->next
}
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
}
newNode->next = cur->next
cur->next = newNode
_size ++
}
void deleteAtIndex(int index) {
if (index >= _size || index < 0 ) {
return
}
LinkedNode* cur = _dummyHead
while (index--){
cur = cur->next
}
LinkedNode* temp = cur->next
cur->next = cur->next->next
delete temp
_size --
}
private:
LinkedNode* _dummyHead
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. 反转链表
心得
- 看到题目想到利用prev来保存前一个值,没有深入,深入应该能想到双指针,还是题目做少了,题感没上来
- 想到保存的位置可能要用特殊如hash来保存,想太多了,刷题有时得看看题目难度,不要想太多
题解
- 双指针法或者递归法,类似2个格子的滑动窗口逐次滑动左右指针替换,替换时类似swap需要temp,感觉就像数组swap的链表版本,直接用对应结构互换即可
/**
* 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* prev = nullptr
ListNode* cur = head
ListNode* temp
while (cur){
temp = cur->next
cur->next = prev
prev = cur
cur = temp
}
return prev
}
}