203. 移除链表元素
难度简单
给你一个链表的头节点
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
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode* newhead = new ListNode(0);
ListNode* tail = newhead;
ListNode* cur = head;
while(cur != nullptr)
{
if(cur->val != val)
{
tail->next = cur;
tail = tail->next;
cur = cur->next;
}
else
{
//tail->next = cur->next;
cur = cur->next;
}
}
tail->next = nullptr;
return newhead->next;
}
};
现在看来真的是一道很基础的题了,最好的方法就是创建一个哨兵位,这样尾插就不需要考虑当前头结点是否为空了。
其次,基本思想就是逐个判断,不是则尾插,是则跳过。最后一行的tail->next = nullptr的原因是如上图的 5 -> 6 ,若没有这条语句,则6也会被带入返回链表中。 不写这条的替代方法就是else语句里tail->next = cur->next;也是同样的目的。
206. 反转链表
难度简单
给你单链表的头节点
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
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* left = nullptr;
ListNode* cur = head;
while(cur!=nullptr)
{
ListNode* right = cur->next;
cur->next = left;
left = cur;
cur = right;
}
return left;
}
};
没什么好说的,多练吧
876. 链表的中间结点
难度简单
给定一个头结点为
head
的非空单链表,返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。
示例 1:
输入:[1,2,3,4,5] 输出:此列表中的结点 3 (序列化形式:[3,4,5]) 返回的结点值为 3 。 (测评系统对该结点序列化表述是 [3,4,5])。 注意,我们返回了一个 ListNode 类型的对象 ans,这样: ans.val = 3, ans.next.val = 4, ans.next.next.val = 5, 以及 ans.next.next.next = NULL.示例 2:
输入:[1,2,3,4,5,6] 输出:此列表中的结点 4 (序列化形式:[4,5,6]) 由于该列表有两个中间结点,值分别为 3 和 4,我们返回第二个结点。提示:
- 给定链表的结点数介于
1
和100
之间。
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode* slow = head;
ListNode* fast = head;
while(fast && fast->next!=nullptr)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
};
非常基础的一个快慢指针。
链表中倒数第k个结点(牛客)
知识点链表双指针
描述
输入一个链表,输出该链表中倒数第k个结点。
示例1
输入:
1,{1,2,3,4,5}复制返回值:
{5}
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
if(nullptr == pListHead)
return nullptr;
ListNode* cur = pListHead;
int num = 0;
while(cur!=nullptr)
{
cur = cur->next;
num++;
}
if(!(k>=1&&k<=num))
return nullptr;
ListNode* fast = pListHead;
ListNode* slow = pListHead;
int n = 0;
while(n++ != k)
{
fast = fast->next;
}
while(fast!=nullptr)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
};
求倒数第k个结点,如倒数第2个,则这个结点和尾结点之后的nullptr的距离就为2,则用双指针的知识,先创建一个快结点,走2步,然后快慢一起走,当快走到nullptr时,慢就是目标的倒数第二个结点。因为距离始终为2(k)。
其实链表长度num没有必要求,但是因为k可能不符合范围,所以求一下。
21. 合并两个有序链表
难度简单
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 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
均按 非递减顺序 排列
class Solution {
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) {
ListNode* newnode = new ListNode{0,nullptr};
ListNode* ret = newnode;
while(list1&&list2)
{
if(list1->valval)
{
newnode->next = list1;
list1 = list1->next;
}
else
{
newnode->next = list2;
list2 = list2->next;
}
newnode = newnode->next;
}
if(list1)
{
newnode->next = list1;
}
else if(list2)
{
newnode->next = list2;
}
return ret->next;
}
};
创建哨兵位利于尾插,谁小则尾插谁。
输入:l1 = [1,2,4], l2 = [1,3,4] 输出:[1,1,2,3,4,4]
拿这个例子来说,其实结束之后l1的1指向了l2的1,l1的2指向了l2的3。
因为每次在新的链表中尾插下一个结点之前,上一个被尾插的结点的链表已经向前走一步了,所以不会导致链表的指向改变之后丢失next的情况,所以没问题。(若值拷贝一个新的结点进行尾插,就不会有这些顾虑了)
CM11 链表分割
较难 通过率:21.95% 时间限制:3秒 空间限制:32M
知识点编程基础链表
描述
现有一链表的头指针 ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class Partition {
public:
ListNode* partition(ListNode* pHead, int x) {
// write code here
if(pHead == nullptr)
return nullptr;
ListNode* g = new ListNode(0);
ListNode* l = new ListNode(0);
ListNode* g_tail = g;
ListNode* l_tail = l;
ListNode* cur = pHead;
while(cur!=nullptr)
{
if(cur->val>=x)
{
g_tail->next = cur;
g_tail = g_tail->next;
cur = cur->next;
}
else
{
l_tail->next = cur;
l_tail = l_tail->next;
cur = cur->next;
}
}
g_tail->next = nullptr;
l_tail->next = g->next;
return l->next;
}
};
设原链表为 1 3 8 5 6 4 7 1 9 4 x = 5 ;
此题不可以只创建一个新链表,然后遍历两边原链表进行尾插,若第一次尾插val
=x的结点,这样是不对的,因为在第一次尾插后,3已经不指向8了,而是指向了4。 解决办法1:就是如上代码:单次遍历,创建两个链表,小于的结点存储在一个链表,大于的存储在另一个链表,最后让小链表的尾接上大链表的头。注意g_tail最后要将next置为空,如上例子,如果不将9的next置为空,则9默认指向4。
其实还有个办法,就是值拷贝如下所示,解决了上述创建一个链表,直接尾插时原链表的元素指向被改变的问题。进行值拷贝就不会出现上述问题了。
class Partition {
public:
ListNode* partition(ListNode* pHead, int x) {
// write code here
ListNode* cur = pHead;
ListNode* newhead = new ListNode(0);
ListNode* tail = newhead;
// 双次遍历,值拷贝
while(cur != nullptr)
{
if(cur->val < x)
{
ListNode* newnode = new ListNode(cur->val);
tail->next = newnode;
tail = newnode;
}
cur = cur->next;
}
cur = pHead;
while(cur != nullptr)
{
if(cur->val >= x)
{
ListNode* newnode = new ListNode(cur->val);
tail->next = newnode;
tail = newnode;
}
cur =cur->next;
}
return newhead->next;
}
};
OR36 链表的回文结构
较难 通过率:29.50% 时间限制:3秒 空间限制:32M
知识点链表栈
描述
对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。
给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。
测试样例:
1->2->2->1返回:true
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class PalindromeList {
public:
bool chkPalindrome(ListNode* A) {
// write code here
// 找中间结点
ListNode* slow = A;
ListNode* fast = A;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
}
ListNode* mid = slow; // 中间结点
// 逆转中间结点
ListNode* left = nullptr;
ListNode* cur = mid;
while(cur != nullptr)
{
ListNode* right = cur->next;
cur->next = left;
left = cur;
cur = right;
}
// 此时left就是那个中间结点
mid = left;
while(mid != nullptr)
{
if(A->val != mid->val)
return false;
A = A->next;
mid = mid->next;
}
return true;
}
};
思路: 1 2 3 4 3 2 1 则先找中间结点,为4,然后以中间结点为头结点,进行链表逆置,之后为1 2 3 1 2 3 4 其实第一个3仍然指向4,因为在逆置 4 3 2 1 时并没有改变第一个3的指向,然后以逆置后的头结点和最初的头结点为开始,进行遍历判断是否相等。
1 2 3 4 4 3 2 1 仍然将后面的4 3 2 1逆置,后为1 2 3 4 1 2 3 4 第一个4仍然指向第二个4,遍历判断是否相等。
突然有一种新的想法,可否创建一个双向链表,然后逐个插入,之后从头和尾向中间遍历判断。