天天看点

LeetCode第321场周赛题解

这周周赛没有什么过多难的 也是可以自己写完的 (芜湖)

第一道题

 6245. 找出中枢整数

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

1 和 x 之间的所有元素之和等于 x 和 n 之间所有元素之和。

返回中枢整数 x 。如果不存在中枢整数,则返回 -1 。题目保证对于给定的输入,至多存在一个中枢整数。

示例 1:

输入:n = 8

输出:6

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

思路: 这道题 一看就要用到前缀和 的知识 这道题在比赛的时候我用的是 前缀和数组 和 后缀和数组一起加逼 得到答案其实并不需要

比赛时候的代码:

class Solution {
public:
    int pivotInteger(int n) {
        vector<int> presum(n);
        vector<int> postsum(n);
        for(int i=0;i<n;++i)
        {
            presum[i]=i+1;
            postsum[i]=i+1;
        }
        for(int i=1;i<n;++i)
        {
            presum[i]+=presum[i-1];
            postsum[n-1-i]+=postsum[n-1-i+1];
        }
        for(int i=0;i<n;++i)
        {
            if(presum[i]==postsum[i]) return i+1;
        }
        return -1;
    }
};
           

多了一个后缀和的代码 其实没必要 统计一下sum是多少就好了 然后再减一下就ok

代码如下:

class Solution {
public:
    int pivotInteger(int n) {
        vector<int> presum(n+1);
        int sum=0;
        for(int i=0;i<=n;++i)
        {
            presum[i]=i+1;
            if(i) presum[i]+=presum[i-1];
            sum+=i;
        }
        for(int i=1;i<=n;++i)
        {
            if(presum[i]==sum-presum[i-1]) return i+1;
        }
        return -1;
    }
};
           

第二题

6246. 追加字符以获得子序列

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

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

子序列是一个可以由其他字符串删除部分(或不删除)字符但不改变剩下字符顺序得到的字符串。输入:s = "coaching", t = "coding"

输出:4

解释:向 s 末尾追加字符串 "ding" ,s = "coachingding" 。

现在,t 是 s ("coachingding") 的一个子序列。

可以证明向 s 末尾追加任何 3 个字符都无法使 t 成为 s 的一个子序列。

思路:

这道题也并不难 一开始理解错了 以为是找子串问题 然后就用了 kmp 提交之后看了 错误示例 我就知道哪里错了 然后 就发现 想复杂了 

好了 闲话不多说 讲思路了 这道题的意思就是 寻找在s 中的 t的 子串 含义 s中含有的t的字符串可以不连贯 但必须是 t的 顺序 意思就是 s=ktr   t = kr t就是 s的子序列 但是 如果 s=ing t=ni 那s需要补充一个i 才能实现 所以很好实现这道题 

代码如下:

class Solution {
public:
    int appendCharacters(string s, string t) {
        int i=0,j=0;
        while(i<s.size())
        {
            if(j==t.size()) return 0;
            if(s[i]==t[j]) j++;
            i++;
        }
        return t.size()-j;
    }
};
           

第三题

6247. 从链表中移除节点

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

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

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

思路 : 利用单调栈 可以维护一个单调小栈 通过维护这个单调小栈 就可以知道 哪些点需要留 哪些点 需要扔掉

deque<int> mp;
        while(h)
        {
            while(!mp.empty() && h->val > mp.back()) mp.pop_back();
            mp.push_back(h->val);
            h=h->next;
        }
           

 再从链表头开始遍历链表 如果他是单调栈中的元素 就保留 不是就删除 

if(s->val!=mp.front())
             {
                s->next==NULL;
                delete s;
            }
           

如果他是单调栈的元素 就需要判断他是不是头节点 我们可以引入一个pre变量 初始化为NULL 可以通过这个来重新将链表串起来

//第一个点
                if(pre==NULL) {
                    head=s;
                    pre=s;
                }
                //后续节点
                else {
                    pre->next=s;
                    pre=s;
                }
           

完整代码如下:

class Solution {
public:
    ListNode* removeNodes(ListNode* head) {
        ListNode* h=head;
        deque<int> mp;
        while(h)
        {
            while(!mp.empty() && h->val > mp.back()) mp.pop_back();
            mp.push_back(h->val);
            h=h->next;
        }
        ListNode* pre=NULL;
        ListNode* temp=head;
        while(temp)
        {
            ListNode* s=temp;
            temp=temp->next;
            if(s->val!=mp.front()) {
                s->next==NULL;
                delete s;
            }
            else {
                mp.pop_front();
                //第一个点
                if(pre==NULL) {
                    head=s;
                    pre=s;
                }
                //后续节点
                else {
                    pre->next=s;
                    pre=s;
                }
            }
        }
        return head;
    }
};
           

第四题

6248. 统计中位数为 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] 。

思路: 这道题 利用的前后缀和 来解题 

#1找到k的位置 同时将 nums数组分别分为 大于 k的(1) 等于k的 (0) 和 小于k的(-1) 方便来计数

// 找出k所在下标idx
        for(int i=0;i<n;i++)
        {
            if(nums[i]==k)
            {
                index = i;
            }
            if(nums[i]<k)
            nums[i] = -1;
            else if(nums[i]==k)
            nums[i] = 0;
            else
            nums[i] = 1;
        }
           

#2 先遍历 idx之后的数 看有几个大于k的 有几个小于k的 利用一张hash_map来计数 分别记录 从idx开始 有几种情况 

// 枚举idx之后的数与idx+idx之前后缀和的和,和为0或1的数目可计入答案
        unordered_map<int,int> m;
        int s = 0;
        for(int i=index+1;i<n;i++)
        {
            s += nums[i];
            m[s] += 1;
        }
           

题目说偶数是记录上中位数的 所以我们可以看2个点 0或者1 的点 这两个点都符合题意 

// 枚举idx与idx之前后缀和的和,和为0或1的数目可计入答案
        for(int i=index;i>=0;i--)
        {
            s += nums[i];
            if(m.find(-s)!=m.end())
            {
                res += m[-s];
            }
            

            if(m.find(1-s)!=m.end())
            {
                res += m[1-s];
            }
            
        }
           

完整代码如下:

class Solution {
public:
    int countSubarrays(vector<int>& nums, int k) {
        int index = 0;
        int res = 0;
        int n = nums.size();
        // 找出k所在下标idx
        for(int i=0;i<n;i++)
        {
            if(nums[i]==k)
            {
                index = i;
            }
            if(nums[i]<k)
            nums[i] = -1;
            else if(nums[i]==k)
            nums[i] = 0;
            else
            nums[i] = 1;
        }

        // 枚举idx之后的数与idx+idx之前后缀和的和,和为0或1的数目可计入答案
        unordered_map<int,int> m;
        int s = 0;
        for(int i=index+1;i<n;i++)
        {
            s += nums[i];
            m[s] += 1;
        }

        m[0] += 1;
        s = 0;

        // 枚举idx与idx之前后缀和的和,和为0或1的数目可计入答案
        for(int i=index;i>=0;i--)
        {
            s += nums[i];
            if(m.find(-s)!=m.end())
            {
                res += m[-s];
            }
            

            if(m.find(1-s)!=m.end())
            {
                res += m[1-s];
            }
            
        }
        return res;
    }
};