leetcode第272周赛


竞赛链接

T1: 2108. 找出数组中的第一个回文字符串


思路

从头枚举,直至找到第一个回文字符串

Code

class Solution {
public:
    bool test(string a){
        string s=a;
        reverse(a.begin(),a.end()); //将原字符串反转再进行比较
        return a==s;
    }
    string firstPalindrome(vector<string>& words) {
        bool flag=false;
        for(auto& i:words){
            if(test(i)){
               return i;
            }
        }
        return "";
    }
};

复杂度分析

时间复杂度:O(∑i*ni),其中 ni为 words 数组中第 i 个字符串的长度。即为遍历寻找第一个回文字符串的时间复杂度。
空间复杂度:O(1)



T2: 2109. 向字符串添加空格


思路

遍历字符串时不断累加,在遍历到字符串指定位置时加上空格

Code

class Solution {
public:
    string addSpaces(string s, vector<int>& a) {
        string ret;
        int n = s.size();
        vector<int> c(n);
        for(int i : a) c[i] = 1;
        for(int i = 0; i < s.size(); ++i) {
            if(c[i]) ret += " ";
            ret += s[i];
        }
        return ret;
    }
};

复杂度分析

  • 时间复杂度:O(n + m),其中 n 是字符串 s 的长度,m 是数组 spaces 的长度。
  • 空间复杂度:O(1) 或 O(n + m),取决于使用的语言中字符串是否可以修改。


T3: 2110. 股票平滑下跌阶段的数目


思路

用双指针来计算连续区间,把所有满足区间的长度加起来(可以用sum(1, n) = n*(n+1)/2)

Code

class Solution {
public:
    long long zong(int len){
        long long le=len;
        long long num=(le-1)*le/2;
        return num;
    }
    long long getDescentPeriods(vector<int>& prices) {
        int n=prices.size();
        long long num=n;
        deque<int>ha;
        for(int r=0;r<n;++r){
            if(ha.empty()){
                ha.push_back(prices[r]);
                continue;
            }
            if(ha.size()>0&&prices[r]==ha.back()-1){
                ha.push_back(prices[r]);
            }
            else{
                if(ha.size()>1)
                    num+=zong(ha.size());
                ha.clear();
                ha.push_back(prices[r]);
            }
        }
        if(ha.size()>=2)
            num+=zong(ha.size());
        return num;
    }
};

复杂度分析

  • 时间复杂度:O(n),其中 n 为 prices 的长度。即为计算每个元素结尾的平滑下降阶段数目并求和的时间复杂度。
  • 空间复杂度:O(1)。


T4: 2111. 使数组 K 递增的最少操作次数


思路

通过观察题目可知: arr[i]只受arr[i-k], arr[i-2k], arr[i-3k], …的影响,所以我们可以分组求出每个组的最长不下降子序列长度再累加,最后用总长度减去累加和即为需要改变的次数

Code

class Solution {
public:
    template<typename T>

    int lis(vector<T> a) {
        vector<T> dp;
        for(auto& x : a) {
            auto it = upper_bound(dp.begin(), dp.end(), x); 

        //因为只要求最长不下降子序列,所以用upper求得大于的那个,然后更改
        //         最长递增子序列用lower

            if(it == dp.end()) dp.push_back(x);  //如果找不打比x大的元素,那么将其加进去
            else *it = x;  //找到的话,对其进行修改
        }
        return dp.size();
    }
    int kIncreasing(vector<int>& a, int k) {
        int n = a.size();
        int ans = 0;
        for(int i = 0; i < k; ++i) {
            vector<int> b;
            for(int j = i; j < n; j += k) {
                b.push_back(a[j]);
            }
            ans += lis(b);
        }
        return n - ans;
    }
};

复杂度分析

  • 时间复杂度:O(nlog kn)。每个序列的长度为 O(kn),寻找其最长递增子序列需要的时间为 O( knlogkn),而一共有 k 个序列,因此总时间复杂度为 O(nlog kn)。
  • 空间复杂度:O(kn),即为寻找单个序列的最长递增子序列时,数组 f 需要的空间。

额外拓展

本题采用的方法是分组然后求最长不下降子序列。
如果题目里的K递增的定义被改成严格递增,是不能用分组然后求最长递增子序列来做的,因为题目另一个限制条件是数组里必须存正整数,那么类似2,1,2,3,4这样的序列是不能改成0,1,2,3,4的,这种情况下难道只能暴力求解了吗?

答:把每个数减去其下标,然后对所有正整数求最长非降子序列。

举个例子,现在每 k 个数选一个数,假设选出来的数组是 [3,2,4,5,5,6,6]。
每个数减去其下标后就是 [ 3,1,2,2,1,1,0]。

对这个数组中的正整数求最长非降子序列,那就是 [1,1,1] 了,对应原始数组的[ *, 2 , * , * , 5 , 6 , * ],这三个数字保留,其余数字修改完成后就是 [ 1,2,3,4,5,6,7],符合严格递增且均为正整数的要求。

注:上述减去下标的技巧,主要是为了能让保留的数字之间可以容纳严格递增的数字。否则,若直接按照最长严格递增子序列的求法,会得到例如[ * , 2 , 4 , 5 , * , 6 , *] 这样的错误结果。


个人总结


本周题目比较简单,但第二题被卡了,本想暴力直接插入空格,却tle一发,浪费了很久。最后一题没有仔细审题,以致于一直卡在不知道该如何分组在lis。总结就是,手速还不够快,遇到简单题第一时间没能写出解法,平时练习还有欠缺,还有下次审题要仔细,与其罚坐不如好好审题!


文章作者: 再也不会
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 再也不会 !
  目录