leetcode---357单周赛

本文介绍了四个编程问题:故障键盘的模拟、判断数组是否可拆分、找出最安全路径的策略和子序列最大优雅度的贪心解法。涉及时间复杂度优化、数组操作和搜索算法应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目列表

2810. 故障键盘

2811. 判断是否能拆分数组

2812. 找出最安全路径

2813. 子序列最大优雅度

一、故障键盘

 这题可以直接模拟,时间复杂度是O(n^2),代码如下

class Solution {
public:
    string finalString(string s) {
        string x;
        for(int i=0;i<s.size();i++){
            if(s[i]=='i'){
                reverse(x.begin(),x.end());
            }else{
                x+=s[i];
            }
        }
        return x;
    }
};

当然还有一种优化方法,时间复杂度为O(n)

class Solution {
public:
    string finalString(string s) {
        deque<char> t;//双端队列
        bool flag=true;
        for(auto x:s){
            if(x=='i'){
                flag=!flag;
            }else if(flag){
                t.push_back(x);
            }else{
                t.push_front(x);
            }
        }
        return flag?string(t.begin(),t.end()):string(t.rbegin(),t.rend());
    }
};

 二、判断是否能拆分数组

 这题主要看你有没有明白题目的意思,题目的要求我们将数组拆分成一个个单个元素,并且在拆分过程中满足上诉两个条件,好,根据条件二,我们肯定是每次将数组分成一个单个元素另一个集合,因为这样最有可能使另一个集合满足条件二

按这个思路正常来说,我们会比较数组两端的数字,然后删除较小的那个,以便让剩下的元素集合满足条件二,但是提交后会有一个反例:[9, 2, 5, 7, 2]  12,按照我们之前所想,我们最后剩下的元素会是[9,2],很显然不符合要求,但是这个例子是能过的,因为只要我们最后剩下的元素是[5,7],就能成功拆分哎,看到这里,我们应该就能想到只要有两个连续元素和>=m,那么无论怎么拆分,我们都能保证剩下的集合元素之和>=m(只要这两个关键元素一直在集合中,而这一点我们很容易办到)

注意两个坑:

1.当数组大小为1时,一定满足条件

2.当数组大小为2时,一定也满足条件,因为拆分一次,就直接成为两个单一元素

(如不注意,恭喜直接喜提5/10分钟)

代码如下

class Solution {
public:
    bool canSplitArray(vector<int>& nums, int m) {
        if(nums.size()==1||nums.size()==2)return true;
        for(int i=1;i<nums.size();i++){
            if(nums[i-1]+nums[i]>=m)
                return true;
        }
        return false;
    }
};

 三、找出最安全路径

 这题的思路简单,但是代码量很大,我们首先要算出各个点的安全系数,在用二分法找到答案,这里在求安全系数的时候注意不能求点到小偷的距离,而应该从小偷的位置向外扩展得到其他点的安全系数(用bfs或者dfs都可以),否则会超时,其次二分法的思路来自关键信息---最大化的最小值/最小化的最大值,(简单的说就是当我们知道一个答案区间,并且不知道要找的值,但是我们明确要找的值会尽可能的小或大,遇到这种情况时,可以想想二分)

const int dir[4][2] = {0, 1, 1, 0, -1, 0, 0, -1};
int**dis;
bool check(int key,int n){
    bool vis[n][n];
    memset(vis,0,sizeof(vis));
    int queue[n*n][2];
    int head=0,tail=0;
    queue[tail][0]=0;
    queue[tail++][1]=0;
    vis[0][0]=true;
    while(head!=tail){
        int x=queue[head][0],y=queue[head++][1];
        for(int k=0;k<4;k++){
            int x0=x+dir[k][0],y0=y+dir[k][1];
            if(x0>=0&&x0<n&&y0>=0&&y0<n&&dis[x0][y0]>=key&&!vis[x0][y0]){
                vis[x0][y0]=true;
                queue[tail][0]=x0,queue[tail++][1]=y0;
            }
        }
    }
    return vis[n-1][n-1];
}
int maximumSafenessFactor(int** grid, int gridSize, int* gridColSize){
    int n=gridSize;
    int queue[n*n][2];
    dis=(int**)malloc(sizeof(int*)*n);
    for(int i=0;i<n;i++){
        dis[i]=(int*)malloc(sizeof(int)*n);
        memset(dis[i],-1,sizeof(int)*n);
    }
    int head=0,tail=0;
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++){
            if(grid[i][j]){
                queue[tail][0]=i;
                queue[tail++][1]=j;
                dis[i][j]=0;
            }
        }       
    }

    //标记安全系数
    while(head!=tail){
        int x=queue[head][0],y=queue[head++][1];
        for(int k=0;k<4;k++){
            int x0=x+dir[k][0],y0=y+dir[k][1];
            if(x0>=0&&x0<n&&y0>=0&&y0<n&&dis[x0][y0]<0){
                queue[tail][0]=x0,queue[tail++][1]=y0;
                dis[x0][y0]=dis[x][y]+1;
            }
        }
    }

    //二分查找答案
    int left=0,right=fmin(dis[0][0],dis[n-1][n-1]);
    while(left<=right){
        int mid=left+(right-left)/2;
        if(check(mid,n))left=mid+1;
        else right=mid-1;
    }
    for(int i=0;i<n;i++)
        free(dis[i]);
    free(dis);
    return right;
}

 四、子序列最大优雅度

 这题的思路是贪心,其实正常来说,看到这种题目第一反应应该是选或不选的dfs,但是这题的数据范围太大了,我们只能往贪心的思路上走,那么我们该怎么贪呢?或者说我们该怎么在众多方案里找到那个最优的方案呢?生活中买东西常说货比三家,其实这题就是了,关键是我们怎么比较方案的优劣。

首先要比较首先得有个标准方案,然后在拿其他的方案跟它比较,找到最好的,而这题很明显,我们将profit最大的k个作为一个标准,然后看删除哪个加入哪个有可能让优雅度更大

 代码如下

int cmp(int**p1,int**p2)
{
    return (*p2)[0]-(*p1)[0];
}
long long findMaximumElegance(int** items, int itemsSize, int* itemsColSize, int k){
    //将利润从大到小排序
    qsort(items,itemsSize,sizeof(int*),cmp);
    int stack[itemsSize];//记录类型重复出现的最小利润
    int top=0;
    int vis[itemsSize+1];//记录出现过的种类
    long long cnt=0;//记录种类的数量
    memset(vis,0,sizeof(vis));
    long long ans=0,total=0;
    for(int i=0;i<itemsSize;i++){
        if(i<k){//将前k个作为比较的基准,直接加入total
            total+=items[i][0];
            if(vis[items[i][1]]==0){
                vis[items[i][1]]=1;
                cnt++;
            }else{//如果是多次出现,可以进入stack中
                stack[top++]=items[i][0];
            }
        }else if(top&&vis[items[i][1]]==0){//当stack不为空且这个种类没有出现过
            total-=stack[--top];
            total+=items[i][0];
            vis[items[i][1]]=1;
            cnt++;
        }
        ans=fmax(ans,total+cnt*cnt);
    }
    return ans;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值