前两天去了曲江书城,看了一上午阿西莫夫的银河帝国系列
感觉已经喜欢上了那里,以后抽空趁没有疫情的时候还要去
链表:7~8天
主要是一些对于链表,最基本数据结构的基本操作
有一些题还是需要写写画画的,例如反转链表,第一次学的时候就是很久搞不明白
目录
141. 环形链表
难度简单1530收藏分享切换为英文接收动态反馈
给你一个链表的头节点 head
,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos
不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true
。 否则,返回 false
。
示例 1:
输入:head = [3,2,0,-4], pos = 1 输出:true 解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0 输出:true 解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1 输出:false 解释:链表中没有环。
提示:
- 链表中节点的数目范围是
[0, 104]
-105 <= Node.val <= 105
pos
为-1
或者链表中的一个 有效索引 。
进阶:你能用 O(1)
(即,常量)内存解决此问题吗?
方法一:首先发现是找环问题,那么环,再次出现,意味着可以用哈希表unordered_map来进行判断,遍历链表,当出现已经遍历过的结点,则说明,出现了环
时间复杂度,空间复杂度均为O(N)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
bool hasCycle(ListNode *head)
{
unordered_set<ListNode *>set;
while(head)
{
if(set.count(head))
return true;
set.insert(head);
head=head->next;
}
return false;
}
};
方法二:追及问题,判断是否有环
用两个指针,一个跑的快(next->next),一个跑的慢(next),同时遍历链表,如果链表中有环,那么两个指针必会在环上相遇
时间复杂度O(N),空间复杂度O(1)
class Solution {
public:
bool hasCycle(ListNode* head) {
if (head == nullptr || head->next == nullptr) {
return false;
}
ListNode* slow = head;
ListNode* fast = head->next;
while (slow != fast) {
if (fast == nullptr || fast->next == nullptr) {
return false;
}
slow = slow->next;
fast = fast->next->next;
}
return true;
}
};
21. 合并两个有序链表
难度简单2504收藏分享切换为英文接收动态反馈
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 1:
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]
示例 2:
输入:l1 = [], l2 = [] 输出:[]
示例 3:
输入:l1 = [], l2 = [0] 输出:[0]
提示:
- 两个链表的节点数目范围是
[0, 50]
-100 <= Node.val <= 100
l1
和l2
均按 非递减顺序 排列
使用递归,将各个结点连接,建立一条新链表的过程
/**
* 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* mergeTwoLists(ListNode* list1, ListNode* list2)
{
if(list1==NULL)
return list2;
else if(list2==NULL)
return list1;
else if(list1->val<list2->val)
{
list1->next=mergeTwoLists(list1->next,list2);
return list1;
}
else
{
list2->next=mergeTwoLists(list2->next,list1);
return list2;
}
}
};
203. 移除链表元素
难度简单950收藏分享切换为英文接收动态反馈
给你一个链表的头节点 head
和一个整数 val
,请你删除链表中所有满足 Node.val == 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 输出:[]
提示:
- 列表中的节点数目在范围
[0, 104]
内 1 <= Node.val <= 50
0 <= val <= 50
非常巧妙地递归解法,也源于链表本身就有递归的性质
/**
* 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) {
if(head==NULL)
return head;
head->next=removeElements(head->next,val);
return head->val==val?head->next:head;
}
};
206. 反转链表
难度简单2603收藏分享切换为英文接收动态反馈
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
示例 1:
输入:head = [1,2,3,4,5] 输出:[5,4,3,2,1]
示例 2:
输入:head = [1,2] 输出:[2,1]
示例 3:
输入:head = [] 输出:[]
提示:
- 链表中节点的数目范围是
[0, 5000]
-5000 <= Node.val <= 5000
进阶:链表可以选用迭代或递归方式完成反转。你能否用两种方法解决这道题?
经典解法是一个割裂逆置法,相当于先逆置前2个,再逆置前3个,这样一直逆置下去,如果用递归其实是相同的思路
这里只给出常见的递推解法
/**
* 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 *pre=nullptr;
ListNode *cur=head;
while(cur)
{
ListNode *nex=cur->next;
cur->next=pre;
pre=cur;
cur=nex;
}
return pre;
}
};
83. 删除排序链表中的重复元素
难度简单813收藏分享切换为英文接收动态反馈
给定一个已排序的链表的头 head
, 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。
示例 1:
输入:head = [1,1,2] 输出:[1,2]
示例 2:
输入:head = [1,1,2,3,3] 输出:[1,2,3]
提示:
- 链表中节点数目在范围
[0, 300]
内 -100 <= Node.val <= 100
- 题目数据保证链表已经按升序 排列
简单水题
/**
* 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* deleteDuplicates(ListNode* head)
{
if(!head)
return head;
ListNode* p=head;
while(p->next)
{
if(p->val==p->next->val)
{
p->next=p->next->next;
}
else
p=p->next;
}
return head;
}
};
链表由于其自身结构特性,有大量运用递归的算法,今后需要注意