Leetcode第321场周赛

本文解析了LeetCode中的三个问题:寻找中枢整数的算法,通过追加字符使字符串成为子序列的最少操作,以及从链表中移除节点的解决方案。通过实例演示和代码实现,探讨了如何在给定范围内高效解决这些技术挑战。
摘要由CSDN通过智能技术生成

第一题

LeetCode 2485. 找出中枢整数

给你一个正整数 n ,找出满足下述条件的 中枢整数 x :

1 和 x 之间的所有元素之和等于 x 和 n 之间所有元素之和。
返回中枢整数 x 。如果不存在中枢整数,则返回 -1 。题目保证对于给定的输入,至多存在一个中枢整数。

示例 1:

输入:n = 8
输出:6
解释:6 是中枢整数,因为 1 + 2 + 3 + 4 + 5 + 6 = 6 + 7 + 8 = 21 。

示例 2:

输入:n = 1
输出:1
解释:1 是中枢整数,因为 1 = 1 。

示例 3:

输入:n = 4
输出:-1
解释:可以证明不存在满足题目要求的整数。

提示:

1 <= n <= 1000

分析:

我们需要判断是否存在一个在1~n中的数,使得1 + 2 + 3 + … +i
i + (i + 1) + (i + 2) + … +n相等
。由于数据范围只有1000,所以可以直接利用求和公式暴力求解。时间复杂度O(N)。

代码

class Solution {
public:
    int pivotInteger(int n) {
        int ans = -1;
        for(int i = 1;i <= n;i++){
            int a = (i+1)*i/2;
            int b = (i + n)*(n-i+1)/2;
            if(a == b){
                ans = i;
                break;
            }
        }
        return ans;
    }
};

第二题

LeetCode 2486. 追加字符以获得子序列

给你两个仅由小写英文字母组成的字符串 s 和 t 。

现在需要通过向 s 末尾追加字符的方式使 t 变成 s 的一个 子序列 ,返回需要追加的最少字符数。

子序列是一个可以由其他字符串删除部分(或不删除)字符但不改变剩下字符顺序得到的字符串。

示例 1:

输入:s = “coaching”, t = “coding”
输出:4
解释:向 s 末尾追加字符串 “ding” ,s =“coachingding” 。 现在t是(“coachingding”) 的一个子序列。 可以证明向 s 末尾追加任何 3个字符都无法使 t 成为 s 的一个子序列。

示例 2:

输入:s = “abcde”, t = “a”
输出:0
解释:t 已经是 s (“abcde”) 的一个子序列。

示例 3:

输入:s = “z”, t = “abcde”
输出:5
解释:向 s 末尾追加字符串 “abcde” ,s = “zabcde” 。
现在,t 是 s (“zabcde”) 的一个子序列。 可以证明向 s 末尾追加任何 4 个字符都无法使 t 成为 s 的一个子序列。

提示:

1 <= s.length, t.length <= 105
s 和 t 仅由小写英文字母组成

分析:

我们先让s 和 t进行匹配,当 s 中没有能与 t中字符相匹配的字符时,此时 t 剩余的还没匹配的字符数量就是答案。时间复杂度O(N)

代码:

class Solution {
public:
    int appendCharacters(string s, string t) {
        int m = s.size(),n = t.size();
        int j = 0;
        for(int i = 0;i < m;i++){
            //成功匹配则 j 往后移
            if(j < n && s[i] == t[j]) j++;
            //当此时已经完全匹配,就提前退出循环
            if(j == n) break;
        }
        //此时的 n - j 就是t剩下的还没被匹配的字符数量
        return n - j;
    }
};

第三题

LeetCode 2487. 从链表中移除节点

给你一个链表的头节点 head 。

对于列表中的每个节点 node ,如果其右侧存在一个具有 严格更大 值的节点,则移除 node 。

返回修改后链表的头节点 head 。

示例 1:

在这里插入图片描述

输入:head = [5,2,13,3,8]
输出:[13,8]
解释:需要移除的节点是 5 ,2 和 3 。

  • 节点 13 在节点 5 右侧。
  • 节点 13 在节点 2 右侧。
  • 节点 8 在节点 3 右侧。
示例 2:

输入:head = [1,1,1,1]
输出:[1,1,1,1]
解释:每个节点的值都是 1 ,所以没有需要移除的节点。

提示:

给定列表中的节点数目在范围 [1, 1 0 5 10^5 105] 内
1 <= Node.val <= 1 0 5 10^5 105

分析:

按照题目的规则,我们只要在纸上简单的模拟一些就可以得出结论:剩下的一条链表肯定是一条单调不增的链表
例如:[5,2,13,3,13,7,12,8,9,12]
最终的结果为:[13,13,12,12]
所以我们只需要先将答案的结点先求出来,然后再将这些答案结点连起来就好了。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码:

class Solution {
public:
    ListNode* removeNodes(ListNode* head) {
        //用vector模拟单调栈
        vector<int> q;
        ListNode* cur = head;
        while(cur){
             //将q中 小于 cur->val 的元素全部弹出去
             //例如:此时q 中的元素为 9 , 5 , 2 ,2 
             //此时的cur->val = 6;
             //经过如下操作 q 中只剩 9 一个元素了
            while(!q.empty() && cur->val > q.back()) q.pop_back();
            q.push_back(cur->val);
            cur = cur->next;
        }

        int i = 0;
        //定义哨兵结点
        ListNode* dummy = new ListNode(-1);
        //定义指向cur结点的前一个结点的指针
        ListNode* pre = dummy;
        cur = head;
        while(cur){
            //如果当前值 等于 答案数组里的值 就进行操作
            if(cur->val == q[i]){
                pre->next = cur;
                pre = cur;
                i++;
            }
            cur = cur->next;
        }
        return dummy->next;
    }
};

第四题

LeetCode 2488. 统计中位数为 K 的子数组

给你一个长度为 n 的数组 nums ,该数组由从 1 到 n 的 不同 整数组成。另给你一个正整数 k 。

统计并返回 num 中的 中位数 等于 k 的非空子数组的数目。

注意:

数组的中位数是按 递增 顺序排列后位于 中间 的那个元素,如果数组长度为偶数,则中位数是位于中间靠 左 的那个元素
例如,[2,3,1,4] 的中位数是 2 ,[8,4,3,5,1] 的中位数是 4 。 子数组是数组中的一个连续部分。

示例 1:

输入:nums = [3,2,1,4,5], k = 4
输出:3
解释:中位数等于 4 的子数组有:[4]、[4,5] 和 [1,4,5]。

示例 2:

输入:nums = [2,3,1], k = 3
输出:1
解释:[3] 是唯一一个中位数等于 3 的子数组。

提示:

n == nums.length
1 <= n <= 1 0 5 10^5 105
1 <= nums[i], k <= n
nums 中的整数互不相同

分析:

给定的数组包含1~n,共n个不同的元素,并且k <= n,所以k是肯定存在数组中的。
按照题目要求 求子数组的中位数为k 的数量
我们可以将其这样转化:
让 大于 k的数变为 1,小于k的数变为-1,等于k的数是0。这样我们就只需要求能让子数组的和为 0 或者 为 1 的数量就好了
子数组的和为1:是因为题目要求,当子数组数量是偶数时,中位数是靠左边的那个数。
第一步是先找到中位数k在数组中的位置 pos
接着就是分别枚举0 ~ pos-1,pos + 1 ~ n的情况,我们需要开一个哈希表来记录个数

在这里插入图片描述

代码:

class Solution {
public:
    int countSubarrays(vector<int>& nums, int k) {
        int n = nums.size();
        int pos = 0;
        //寻找中位数在数组中的位置pos
        for(int i = 0;i < n;i++){
            if(nums[i] == k){
                pos = i;
                break;
            }
        }
        //记录个数
        unordered_map<int,int> cnt;
        //k本身也算作一个答案
        cnt[0] = 1;
        int sum = 0;
        //从pos左边枚举到开始的位置
        for(int i = pos-1;i >= 0;i--){
            if(nums[i] > k) sum++;
            else sum--;
            //记录pos左边的情况
            cnt[sum]++;
        }
        //先加上左边的结果
        int ans = cnt[0] + cnt[1];
        sum = 0;
        //枚举pos右边到n的情况
        for(int i = pos + 1;i < n;i++){
            if(nums[i] > k) sum++;
            else sum--;
            //如果cnt 存在元素 使得其 + sum = 0 或者是 1 那么就加入到结果里面
            ans += cnt[-1*sum];
            ans += cnt[1-sum];
        }
        return ans;
    }
};
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值