3_1 删除链表中的节点
Answer-将被删节点下一个val复制到待删除节点,然后将待删节点直接连接到下下一个节点即可。
学到:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
c++中结构体可以看作一个权限为public的类。其拥有成员变量、成员函数、构造函数等。
ListNode(int x) : val(x), next(NULL) {}就是构造函数的列表初始化操作。
3_2 删除链表的倒数第N个节点,给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
My-获取长度再跑到待删除节点前节点进行删除即可
Answer-快慢指针、栈
学到:初始化一个链表
结构体:
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) {}
};初始链表并链上:
ListNode* head[5];
for (int i = 0; i < 6; i++)
{
head[i] = new ListNode(i + 1);
}
for (int i = 0; i < 6; i++)
{
head[i]->next = head[i + 1];
}
head[5]->next = nullptr;注意:结构体声明再.h中只需要include .h即可不用包含.cpp文件,不然会导致多重定义的符号的错误。
3_3 给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
My-头插法
Answer-递归方法,1->2->3->4->5
- 1->2->3->4<-5
- 1->2->3<-4<-5
- 1->2<-3<-4<-5
- 1<-2<-3<-4<-5
核心 head->next->next = head ;
注意:
ListNode* reverseList(ListNode* head) {
ListNode* p = head;
ListNode* result = new ListNode();
result->next = nullptr;
while(p != nullptr)
{
ListNode *q = p;
p = p->next;
q->next = result->next;
result->next = q;
}
return result->next;
}
头插法时,一定让 p = p->next;紧跟ListNode *q = p;后,不然就找不到原本的顺序了。
3_4 合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
My-双指针分别遍历若当前所遍历list1节点小于当前遍历list2节点,则当前list1插入合并链表,并且list1当前节点指针后移,反之list2指针加入合并链表并后移。若相等则都加入合并链表并后移。
Answer-递归,子问题划分,即list1与list2中较小的指向调用递归函数返回的结果,递归参数为(较小的节点的next和另一个链表中的节点)。
退出条件:
if (list1 == NULL) {
return list2;
}
if (list2 == NULL) {
return list1;
}
学习到:写法更加简易
r尾插p直接
r->next = p;
r = r->next;
即可
3_5 回文链表
给你一个单链表的头节点 head
,请你判断该链表是否为回文链表。如果是,返回 true
;否则,返回 false
。
My-借助栈先遍历入栈,再重新遍历并 逐个出栈比较,出现不相等即是非回文链表。
Answer-方法一:复制val到数组再进行前后向中间走进行双指针判断。
方法二:递归,可以利用递归进行链表的方向遍历
void print_node_val(ListNode *head)
{
if(head != nullptr)
{
print_node_val(head->next);
cout << head->val << endl;
}
}
currentNode 指针是先到尾节点,由于递归的特性再从后往前进行比较。frontPointer 是递归函数外的指针。若 currentNode.val != frontPointer.val 则返回 false。反之,frontPointer 向前移动并返回 true。
bool recursivelyCheck(ListNode* currentNode) {
if (currentNode != nullptr) {
if (!recursivelyCheck(currentNode->next)) {
return false;
}
if (currentNode->val != frontPointer->val) {
return false;
}
frontPointer = frontPointer->next;
}
return true;
}
来源:力扣(LeetCode)
学到了:
C++栈的使用
//导入
include ”stack“
//初始栈
stack<int> mystack;
//入栈
mystack.push(val);
//出栈,返回为void
mystack.pop();
//获取栈顶元素
int a = mystack.top();
//栈空判断,空返回1非空为0
mystack.empty();
3_6判断链表是否有环
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
Answer-
方法一:快慢指针 两个指针一个走的快一个慢,若存在环则快指针一定会追上慢指针。
方法二:哈希表,注意哈希表存储节点。
核心:unordered_set<ListNode*> myset;
回顾:unorderd_set操作
定义unordered_set<datatype> set_name;
添加 myset.emplace(value);
查找myset.find(value); //返回为一个迭代器,auto类型 若未找到则返回myset.end() 否则返回一个正向迭代器。