2021-10-06每日刷题打卡
力扣——链表
1171. 从链表中删去总和值为零的连续节点
给你一个链表的头节点 head,请你编写代码,反复删去链表中由 总和 值为 0 的连续节点组成的序列,直到不存在这样的序列为止。
删除完毕后,请你返回最终结果链表的头节点。
你可以返回任何满足题目要求的答案。
(注意,下面示例中的所有序列,都是对 ListNode 对象序列化的表示。)
示例 1:
输入:head = [1,2,-3,3,1]
输出:[3,1]
提示:答案 [1,2,1] 也是正确的。
设置一个头结点o,头结点后跟着head,创建两个结点p和q,把o的地址赋给p,一个数num来计算结点值相加的和,一个bool变量b=false,开始遍历,当p为NULL时退出遍历,一开始如果b为false,就令q=p->next,如果b为true就把b变成false,这里为什么这么做后面会说,然后再开始遍历,当q为空时结束遍历,每遍历一个结点就让num加上当前结点的值,判断num是否为0,如果为0,就让p->next指向q->next(即删除总和为0的那一段)为防止出现疏漏,当删除操作发生后,把p的位置挪回头结点o处重新遍历,把b变为ture,然后直接break退出当前循环,内测的while循环结束时判断一下,如果b为true说明发生删除操作,就不让p往下移动一位了,而是让q=o.next,这也是为什么前面要判断b的原因,如果没有这一步,会使q的值跳过一个结点,可能会使结果有误差。如果b为false,说明没有发生删除操作,p往下遍历一位。最后所有遍历都完成后,返回头结点o的next。
/**
* 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* removeZeroSumSublists(ListNode* head) {
ListNode* p, * q, o;
p = &o;
p->next = head;
int num = 0;
bool b = false;
while (p->next != NULL)
{
if (!b)
{
q = p->next;
}
else {
b = false;
}
while (q != NULL)
{
num += q->val;
if (num == 0)
{
p->next = q->next;
p = &o;
b = true;
break;
}
q = q->next;
}
num = 0;
if (b)
{
q = o.next;
}
else
{
p = p->next;
}
}
return o.next;
}
};
143. 重排链表
给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0 → L1 → … → Ln-1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
输入: head = [1,2,3,4]
输出: [1,4,2,3]
这里用到快慢指针,慢指针p和快指针q,p和q一开始都指向开头,遍历开始p就往下走一位,q直接走到结尾,然后q->next=p->next,q再连到p->next上,这里我们应该再设置一个指针s,在遍历时s和q一起遍历,但s是作为q的前置结点,当q插入到p->next时,s的next从q改为NULL,这样做是防止出现环状结构,插入完q后,p往下走一个位置(走一个就行,因为当回到遍历开头时他自己会再走一个位置)。
创建三个结点p,q,s。p->next=head,开始遍历,当p的next为空或next的next为空时退出,因为这时说明p已经是最后一个或倒数第二个结点了,重排操作就无意义了所以直接结束遍历就好。然后按照我们上面说的开始遍历就行。
/**
* 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:
void reorderList(ListNode* head) {
ListNode * p, * q, * s;
p=(ListNode*)malloc(sizeof(ListNode));
p->next = head;
q = head;
while (p->next != NULL&&p->next->next!=NULL)
{
p = p->next;
while (q->next != NULL)
{
s = q;
q = q->next;
}
s->next = NULL;
q->next = p->next;
p->next = q;
p = p->next;
}
}
};
25. K 个一组翻转链表
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
进阶:
你可以设计一个只使用常数额外空间的算法来解决此问题吗?
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
示例 1:
输入:head = [1,2,3,4,5], k = 2
输出:[2,1,4,3,5]
既然说了翻转,那又要请到我们的206. 反转链表,但我们这里要改一下,原本参数只传一个头结点就行,现在我们要传一个头结点和一个尾结点。然后也返回给我们一个头结点一个尾结点,这样方便我们把链表接回去。创建一个头结点start,后面跟着head,一个结点end是主要用来遍历的,同时是断链的尾节点,一个num=0是计数,两个结点s需要翻转的链表的头结点,r是end在当尾节点时先存好后面还没遍历到的位置,p是指向head的头指针,q是用来给s提供结点位置的指针,一开始在head的位置。开始遍历,当end为空时结束遍历,先num++,因为一开始end就在第一个结点了,所以要先计数,如果是把num设置为1,然后把num++放在end遍历操作后的话,就会导致跳过一个结点。num++后判断一下num是否等于k,如果等于,开始断链,我们把q的位置赋给s,当作断链的头结点,r=end->next,用来维护还没遍历到的节点,end就作为尾节点,要把end的next改成NULL,不然会死循环,然后我们把头结点为s,尾节点为end的这一段链表拿去翻转,返回给我们翻转后的头结点和尾节点,但有个问题,我们不能直接返回两个节点,所以我们用vector容器,用它存放两个节点后返回给我们,0处位置放头,1处位置放尾。我们用一个vector容器来接收它,要注意,这个容器一开始要先用resize来预留空间,不然会报错。然后p连上v[0],然后p开始遍历,遍历到p->next为NULL时结束遍历,让p->next=r,即把断链重新装回来。end=r,拿回还没遍历好的那部分链表,继续遍历。但这里有一点要注意的地方,end拿回没遍历的那部分链表相当于是让end往下走了一位,但我们结束翻转操作时下面还有一个end向下移动一位的操作,所以num要先设置为1,防止跳过一个节点,而且在下面的遍历操作开始时要先判断一下当前end是否为NULL,如果为NULL就直接break结束整个遍历。最后返回o.next,就是我们要的结果了。
/**
* 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:
vector<ListNode*> reverseList(ListNode* head,ListNode* end) {
ListNode* p, * q, * o;
vector<ListNode*>v;
p = end->next;
q = head;
while (q != NULL)
{
o = q->next;
q->next = p;
p = q;
q = o;
}
v.push_back(p);
v.push_back(head);
return v;
}
ListNode* reverseKGroup(ListNode* head, int k) {
if (k == 1)
{
return head;
}
ListNode* p, * q, o, * end, * s,*r;
vector<ListNode*>v;
v.reserve(2);
p = &o;
p->next = head;
end = head;
q = head;
int num = 0;
while (end)
{
num++;
if (num == k)
{
num = 0;
r = end->next;
s = q;
end->next = NULL;
v = reverseList(s, end);
p->next = v[0];
while (p->next)
{
p = p->next;
}
end = r;
p->next = end;
q = q->next;
num++;
}
if(end==NULL)
{
break;
}
end = end->next;
}
return o.next;
}
};
力扣——每日一题
414. 第三大的数
给你一个非空数组,返回此数组中 第三大的数 。如果不存在,则返回数组中最大的数。
示例 1:
输入:[3, 2, 1]
输出:1
解释:第三大的数是 1 。
一眼想到的办法,直接sort,然后从容器末尾开始遍历,先把a赋值nums[nums.size()-1],即最大的那个数,遍历从nums.size()-2开始,再设定一个值j=1,来计算是否是第3大的数。每遍历一个数,就拿那个数和a对比,如果不相等就把j++,a=nums[i],判断j是否为3,如果为3就直接把a返回就行。如果遍历完了j也不为三,那就直接return nums[nums.size()-1]即最大的那个数。
class Solution {
public:
int thirdMax(vector<int>& nums) {
sort(nums.begin(), nums.end());
int a = nums[nums.size() - 1];
int j = 1;
for (int i = nums.size() - 2; i >= 0; i--)
{
if (a != nums[i])
{
j++;
a = nums[i];
if (j == 3)
{
return a;
}
}
}
return nums[nums.size() - 1];
}
};