题目一:
203. 移除链表元素
思路:
1. 设定一个临时指针temp,逐步遍历链表,遇到符合val的结点就删除
2. 因为头结点为 val 时,需要一个指向头结点的结点,所以设定一个虚拟头结点,并令 temp 指向它
代码:
难点在于头结点的解法和不是头结点的解法能不能混合?如何混合?
1 class Solution {
2 public:
3 ListNode* removeElements(ListNode* head, int val) {
4 //创造虚拟头结点,防止头结点为要删除的值,导致需要两种删除结点的方法
5 ListNode* list = new ListNode();
6 list->next = head;
7 //创造一个指针,遍历链表
8 ListNode* temp = list;
9 //如果要删除元素,需要知道被删除结点的的前一个结点,所以使用temp->next
10 while(temp->next != NULL)
11 {
12 if(temp->next->val == val)
13 {
14 //ListNode* freeNode = temp->next;
15 temp->next = temp->next->next;
16 //free(freeNode);
17 }
18 else temp = temp->next;
19 }
20 return list->next;
21 }
22 };
题目二:
206. 反转链表
初见思路:
1.开始想了两三种思路,但待到开始敲代码时才发现无法指向前一个结点。过了二十多分钟,想了一个三指针的思路,并在纸上模拟成功,就开敲了
代码1:
其实只能算不完美的双指针解法,我没能结合将头结点的解法与非头结点的解法混合在一起
而下面的代码2为双指针解法,看完才觉得妙,非常妙!
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(head == nullptr) return head;
if(head->next == nullptr) return head;
ListNode* c1 = head;
ListNode* c2 = c1->next;
ListNode* c3 = c2->next;
c2->next = c1;
c1->next = nullptr;
if(c3 == nullptr) return c2;
while(c3 != nullptr)
{
c1 = c2;
c2 = c3;
c3 = c3->next;
c2->next = c1;
}
c2->next = c1;
return c2;
}
};
代码2:
1 class Solution {
2 public:
3 ListNode* reverseList(ListNode* head) {
4 //从头结点开始,不用单独考虑头结点是否为空
5 ListNode* c1 = nullptr;
6 ListNode* c2 = head;
7 while(c2 != nullptr)
8 {
9 //定义一个指针,保存c2后面的地址
10 ListNode* c3 = c2->next;
11 c2->next = c1;
12 c1 = c2;
13 c2 = c3;
14 }
15 //当结束循环,c2指向null,c1指向尾结点
16 return c1;
17 }
18 };
题目3:
707. 设计链表
初见:
1. 之前敲过便以为随随便便都可以,但之后却是无尽的debug
2.看视频后解决恍然大悟
思路:
1. 定义结构体
2. 设定私有属性虚拟头结点_dummyHead 和成员长度_size
3. 插入函数需要让_size的范围加1,不然当插入尾结点之后会错误
代码3:
class MyLinkedList {
public:
//构造链表的属性
typedef struct ListNode{
int val;
struct ListNode *next;
ListNode(int val):val(val),next(nullptr){} //构造函数兼初始化
};
MyLinkedList(){
_dummyHead = new ListNode(0); //定义虚拟头结点,初始化链表
_size = 0;
}
//因为虚拟头结点为成员变量,所以成员函数可以直接访问,参数不用添加虚拟头结点
int get(int index) {
if(index >= 0 && index <= _size)
{
ListNode* cur = _dummyHead->next;
//当index为0时循环停止
while(index)
{
cur = cur->next;
index--;
}
return cur->val;
}
return -1;
}
void addAtHead(int val) {
ListNode* new_Node = new ListNode(val);
new_Node->next = _dummyHead->next;
_dummyHead->next = new_Node;
_size++; //链表长度加一
}
void addAtTail(int val) {
//防止头结点不存在,若为_dummyHead->next,且头结点为空,就会报错
//因为结合whlie循环,会重复访问nullptr
ListNode* cur = _dummyHead;
//直到指向尾节点停止,因为尾结点指向nullptr
while(cur->next != nullptr)
{
cur = cur->next;
}
ListNode* new_Node = new ListNode(val);
cur->next = new_Node;
_size++;
}
void addAtIndex(int index, int val) {
//加一是因为新元素会变成链表的末尾,cur = 末尾,index = _size + 1;,所以要+1 index才能访问
if(index >= 0 && index <= _size + 1)
{
ListNode* cur = _dummyHead;
//当index为0时循环停止
while(index)
{
cur = cur->next;
index--;
}
ListNode* new_Node = new ListNode(val);
new_Node->next = cur->next;
cur->next = new_Node;
_size++;
}
}
void deleteAtIndex(int index) {
if(index >= 0 && index <= _size)
{
//同理,需要考虑头结点
ListNode* cur = _dummyHead;
while(index)
{
cur = cur->next;
index--;
}
ListNode* temp = cur->next;
cur->next = cur->next->next;
delete temp;
temp = nullptr;
_size--;
}
}
private:
ListNode* _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);
*/