返回倒数第k个值
LCR 140. 训练计划 IIhttps://leetcode.cn/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/
给定一个头节点为 head
的链表用于记录一系列核心肌群训练项目编号,请查找并返回倒数第 cnt
个训练项目编号。
思路:
双指针,快指针先走cnt步然后快慢指针同时向前走,当快指针为空时慢指针所在位置即为倒是第cnt个编号
class Solution {
public:
ListNode* trainingPlan(ListNode* head, int cnt) {
ListNode *fast=head,*slow=head;
for(int i=1;i<=cnt;i++)
fast=fast->next;
while(fast)
{
fast=fast->next;
slow =slow->next;
}
return slow;
}
};
判断是否构成环
141. 环形链表https://leetcode.cn/problems/linked-list-cycle/
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos
不作为参数进行传递 。仅仅是为了标识链表的实际情况。如果链表中存在环 ,则返回 true
。 否则,返回 false
。
思路:
双指针,一个快指针一个慢指针,快指针每次走两步(有风险:快指针可能为空要特殊处理一下)慢指针走一步。如果两个指针能相遇则有环,如果不能相遇则没有环
class Solution {
public:
bool hasCycle(ListNode *head) {
ListNode *fast=head,*slow=head;
while(fast&&fast->next){
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
return 1;
}
return false;
}
};
删除链表中重复元素
26. 删除有序数组中的重复项https://leetcode.cn/problems/remove-duplicates-from-sorted-array/
给你一个 非严格递增排列 的数组 nums
,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums
中唯一元素的个数。
考虑 nums
的唯一元素的数量为 k
,你需要做以下事情确保你的题解可以被通过:
- 更改数组
nums
,使nums
的前k
个元素包含唯一元素,并按照它们最初在nums
中出现的顺序排列。nums
的其余元素与nums
的大小不重要。 - 返回
k
。
思想:
双指针,快指针如果与慢指针相等快指针++,当快指针不等于慢指针时,慢指针++快慢赋值给慢指针,然后快指针++。直到快指针遍历完数组结束。
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int fast=1,slow=0;
if(nums.size()==1)
return 1;
while(fast<nums.size())
{
if(nums[fast]==nums[slow])
fast++;
else
{
slow++;
nums[slow]=nums[fast];
fast++;
}
}
return slow+1;
}
};
82. 删除排序链表中的重复元素 IIhttps://leetcode.cn/problems/remove-duplicates-from-sorted-list-ii/
给定一个已排序的链表的头 head
, 删除原始链表中所有重复数字的节点,只留下不同的数字 。返回 已排序的链表 。
思路
创建一个虚头节点,前驱节点pre和当前节点cur。如果当前节点的值等于下一个节点的值,就找一个临时变量存下,如果当前节点的值等于临时变量,则开始删除。否则当前节点和前驱节点都移动,最后返回虚头节点的下一个节点。
class Solution {
public:
ListNode* deleteDuplicates(ListNode* head) {
ListNode *Head=new ListNode(0,head);
ListNode*pre=Head,*cur=head;
while(cur&&cur->next)
{
if(cur->val==cur->next->val)
{
int temp=cur->val;//记录要删除的节点
while(cur && cur->val==temp)
{
pre->next=cur->next;
cur=cur->next;
}
}
else
{
cur=cur->next;
pre=pre->next;
}
}
return Head->next;
}
};
最大子数组和
53. 最大子数组和https://leetcode.cn/problems/maximum-subarray/
给你一个整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。子数组是数组中的一个连续部分。
思路:
将数组和与最大和比较,如果数组和大于最大和则更新,否则最大和加下一位数组元素判断有没有当前最大和大。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int max=INT_MIN;
int sum=0;
for(int i=0;i<nums.size();i++)
{
sum+=nums[i];
if(sum>max)max=sum;
if(sum<0)sum=0;
}
return max;
}
};
链表的中间节点
876. 链表的中间结点https://leetcode.cn/problems/middle-of-the-linked-list/
给你单链表的头结点 head
,请你找出并返回链表的中间结点。
如果有两个中间结点,则返回第二个中间结点。
思路:快指针走两步慢指针走一步
class Solution {
public:
ListNode* middleNode(ListNode* head) {
ListNode* fast=head,*slow =head;
while(fast&& fast->next)
{
fast=fast->next->next;
slow=slow->next;
}
return slow;
}
};
合并两个有序链表
21. 合并两个有序链表https://leetcode.cn/problems/merge-two-sorted-lists/
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
思路:
当头节点和中间节点的处理方式不同时手动添加一个虚头节点,
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
//创建虚头节点
ListNode* Head = new ListNode();
ListNode* Tail = Head;
while(l1 && l2)
{
if(l1->val<=l2->val)
{
Tail->next=l1;
l1=l1->next;
}
else
{
Tail->next=l2;
l2=l2->next;
}
Tail=Tail->next;
}
//判断剩余
if(l1) Tail->next=l1;
if(l2) Tail->next=l2;
return Head->next;
}
};
反转链表
206. 反转链表https://leetcode.cn/problems/reverse-linked-list/
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
思路:
定义一个cur代表当前要反转的节点 ,定义pre为空,让cur->next指向pre,此时需要一个next找到后面
(pre是反转要指向的节点 cur是当前要反转的节点 next记录下一个要反转的节点
即cur->next=pre pre=cur cur=next next=next->next)
class Solution {
public:
ListNode* reverseList(ListNode* head) {
if(!head)return head;
ListNode *cur=head,*pre=nullptr,*next=head->next;
while(cur)
{
cur->next=pre;
pre=cur;
cur=next;
if(next)
next=next->next;
}
return pre;
}
};
相交链表
160. 相交链表https://leetcode.cn/problems/intersection-of-two-linked-lists/
给你两个单链表的头节点 headA
和 headB
,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null
。
思路
两个指针,a指针先走链表1然后走链表2,b指针先走链表2在走链表1如果在都走完之前两指针会相遇则两链表相交否则不相交
(
A=A?A->next:headB; 这行代码的意思是,如果A非空,即A指向的节点不为空,则将A指针移向下一个节点,即A=A->next;如果A为空,即已,经达到了链表末尾则让A重新指向headB,即A=headB。这样保证了A指针遍历完链表A后可以继续遍历链表B中的节点。
B=B?B->next:headA; 同理。
)
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
ListNode*a=headA,*b=headB;
while(a!=b)
{
if(a)
a=a->next;
else
a=headB;
b=b?b->next:headA;
}
return a;
}
};
回文链表
LCR 027. 回文链表https://leetcode.cn/problems/aMhZSa/
给定一个链表的 头节点 head
,请判断其是否为回文链表。
如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。
思路
先找到中间节点(快指针走两步慢指针走一步),将后半部分也就是4-1进行反转,比较pre和head链表
class Solution {
public:
bool isPalindrome(ListNode* head) {
ListNode*f=head,*s=head;
while(f&&f->next)
{
f=f->next->next;
s=s->next;
}
ListNode *pre = nullptr, *cur = s, *next = cur->next;
while(cur) {
cur->next = pre;
pre = cur;
cur = next;
if (next) {
next = next->next;
}
}
while(head&&pre)
{
if(head->val!=pre->val)
{
return false;
}
else
{
head=head->next;
pre=pre->next;
}
}
return true;
}
};
删除倒数第k个节点
19. 删除链表的倒数第 N 个结点https://leetcode.cn/problems/remove-nth-node-from-end-of-list/
给你一个链表,删除链表的倒数第 n
个结点,并且返回链表的头结点。
思路
当头节点和非头节点出现差异时设虚头,最后返回虚头->next。
创建虚头的语句 List Node *Head=new ListNode(0,head);
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode*HEAD=new ListNode(0,head);
ListNode *fast=head,*slow =HEAD;
if(!head)return head;
for(int i=0;i<n;i++)
{
fast=fast->next;
}
while(fast)
{
fast=fast->next;
slow=slow->next;
}
slow->next=slow->next->next;
return HEAD->next;
}
};
旋转链表
61. 旋转链表https://leetcode.cn/problems/rotate-list/
给你一个链表的头节点 head
,旋转链表,将链表每个节点向右移动 k
个位置。
思路
坑:k可能大于链表的长度
先求出链表的长度,然后因为k可能大于链表长度这里对k取余,再将链表头尾节点拼接,最后断链。
class Solution {
public:
ListNode* rotateRight(ListNode* head, int k) {
if (!head || !head->next) return head; // 处理链表为空或只有一个节点的情况
ListNode *p = head;
int n = 1;
while (p->next) { // 找到链表长度n
p = p->next;
n++;
}
p->next = head; // 将链表首尾相连形成环状链表
k = n - k % n; // 找到需要断开的位置
for (int i = 0; i < k; i++) {
p = p->next;
}
head = p->next; // 更新新的头节点
p->next = nullptr; // 断开环状链表
return head;
}
};
链表中元素的和
2. 两数相加https://leetcode.cn/problems/add-two-numbers/
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
思路
本题首先要考虑两个问题:一是两个链表长度不相同,二是进位问题。 新建一个链表存储两个链表的和,利用%10和/10取出个位和十位,将对齐位数的和的个位存入链表十位进位,最后遍历新建的链表即为所求。
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
/*
*/
ListNode*head=new ListNode();
ListNode*tail=head;
int carry=0;
while(l1||l2||carry)
{
int n1=l1?l1->val:0;
int n2=l2?l2->val:0;
int sum=n1+n2+carry;
carry=sum/10;//存进位的数字
tail->next=new ListNode(sum%10);
tail=tail->next;
if(l1)
l1=l1->next;
if(l2)
l2=l2->next;
}
return head->next;
}
};