2021-10-06每日刷题打卡

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];
}
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值