leetcode contest 141

一、1089. Duplicate Zeros

给你一个长度固定的整数数组 arr,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。

注意:请不要在超过该数组长度的位置写入元素。

要求:请对输入的数组 就地 进行上述修改,不要从函数返回任何东西

一道难度easy的题,要通过测试很简单,但是一般人都是直接写个空间复杂度为O(n)的算法,比如我。

class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        vector<int> ans;
        int n=arr.size(),i=0;
        while(ans.size()<n&&i<n)
        {
            if(arr[i])
                ans.push_back(arr[i]);
            else
            {
                ans.push_back(0);
                if(ans.size()<n)
                    ans.push_back(0);
            }
            ++i;
        }
        arr=ans;
    }
};

但大神总是能快速地提出高效的解法:空间复杂度O(1):

1、首先计数数组中有多少个零以决定数组一共需要右移几次;

2、右移后超过原数组长度范围的元素不再考虑;

class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        int n=arr.size(),i=0,shift=0;
        while(i+shift<n)
            shift+=(!arr[i++]);
        //将元素右移的过程
        for(i=i-1;shift;--i)
        {
            if(i+shift<n)//一定要有这个判断,因为上一个循环可能是从i+shift==n+1处退出的
                arr[i+shift]=arr[i];
            if(!arr[i])
                --shift,arr[i+shift]=0;
        }
    }
};

二、1090. Largest Values From Labels

我们有一个项的集合,其中第 i 项的值为 values[i],标签为 labels[i]

我们从这些项中选出一个子集 S,这样一来:

  • |S| <= num_wanted
  • 对于任意的标签 L,子集 S 中标签为 L 的项的数目总满足 <= use_limit

返回子集 S 的最大可能的 

思路:做这题的时候一开始我不是很理解题意,看了中文翻译才明白过来(看了discuss区才发现很多人都看不懂题意,英文原题描述得比较模糊)。直接将values从大到小排序然后依次取出可取的元素相加即可。

class Solution {
public:
    int largestValsFromLabels(vector<int>& values, vector<int>& labels, int num_wanted, int use_limit) 
    {
        int n=values.size();
        vector<vector<int>> v;
        unordered_map<int,int> record;
        //每个值对应一个标签,这个是不可变的
        for(int i=0;i<n;++i)
            v.push_back({values[i],labels[i]});
        //排序调用的函数,只对value进行从大到小的排序
        auto cmp=[](vector<int>& a,vector<int>& b){
            return a[0]>b[0];
        };
        sort(v.begin(),v.end(),cmp);
        int cnt=0,ans=0;
        for(int i=0;i<n&&cnt<num_wanted;++i)
        {
            int value=v[i][0],label=v[i][1];

            if(record[label]<use_limit&&cnt<num_wanted)
            {
                ans+=value,++cnt,++record[label];
            }
        }
        return ans;
    }
};

三、1091. Shortest Path in Binary Matrix

在一个 N × N 的方形网格中,每个单元格有两种状态:空(0)或者阻塞(1)。

一条从左上角到右下角、长度为 k 的畅通路径,由满足下述条件的单元格 C_1, C_2, ..., C_k 组成:

  • 相邻单元格 C_i 和 C_{i+1} 在八个方向之一上连通(此时,C_i 和 C_{i+1} 不同且共享边或角)
  • C_1 位于 (0, 0)(即,值为 grid[0][0]
  • C_k 位于 (N-1, N-1)(即,值为 grid[N-1][N-1]
  • 如果 C_i 位于 (r, c),则 grid[r][c] 为空(即,grid[r][c] == 0

返回这条从左上角到右下角的最短畅通路径的长度。如果不存在这样的路径,返回 -1

思路:这是一道典型的求最短路的问题,这种问题我总是优先考虑是否能用BFS解,往往是可以的。需要注意的是离开时的距离就已经是1。

class Solution {
public:
    int shortestPathBinaryMatrix(vector<vector<int>>& grid) {
        if(grid[0][0])
            return -1;
        int rows=grid.size(),cols=grid[0].size();
        queue<vector<int>> q;
        //队列元素为:行、列、已经走过的距离
        q.push({0,0,1});
        int dir[8][2]={{-1,0},{1,0},{0,-1},{0,1},{-1,-1},{-1,1},{1,-1},{1,1}};
        //(row,col)一旦入队即表明该点已经走过,将对应的grid修改为1确保不再走。
        grid[0][0]=1;
        while(!q.empty())
        {
            int n=q.size(),row,col,dis;
            while(n--)
            {
                vector<int> cur=q.front();q.pop();
                row=cur[0],col=cur[1],dis=cur[2];
                
                if(row==rows-1&&col==cols-1)
                    return dis;
                for(int i=0;i<8;++i)
                {
                    int nextr=row+dir[i][0],nextc=col+dir[i][1];
                    if(0<=nextr&&nextr<rows&&0<=nextc&&nextc<cols&&!grid[nextr][nextc])
                        q.push({nextr,nextc,dis+1}),grid[nextr][nextc]=1;
                }
            }
        }
        return -1;
    }
    
};

四、1092. Shortest Common Supersequence

给出两个字符串 str1 和 str2,返回同时以 str1 和 str2 作为子序列的最短字符串。如果答案不止一个,则可以返回满足条件的任意一个答案。

(如果从字符串 T 中删除一些字符(也可能不删除,并且选出的这些字符可以位于 T 中的 任意位置),可以得到字符串 S,那么 S 就是 T 的子序列)

思路:这道题不难想到要先求出两个字符串的最长公共子序列,再由该子序列构造出答案。但在规定时间内我没有构造出来,看了discuss区域大神的解法也发现了我之间求子序列的代码写得不够简洁,因此根据大神的思路重写了一遍代码。

class Solution {
public:
    string shortestCommonSupersequence(string str1, string str2) {
        int n=str1.size(),m=str2.size();
        vector<vector<string>> dp(n+1,vector<string>(m+1));
        //直接求出最长公共子列
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)
            {
                if(str1[i-1]==str2[j-1])
                    dp[i][j]=dp[i-1][j-1]+str1[i-1];
                else
                    dp[i][j]=(dp[i-1][j].size()>dp[i][j-1].size()?dp[i-1][j]:dp[i][j-1]);
            }
        string ans;
        int p1=0,p2=0;
        for(char ch:dp[n][m])
        {
             while(p1<n&&str1[p1]!=ch)
                ans+=str1[p1++];
             while(p2<m&&str2[p2]!=ch)
                ans+=str2[p2++];
             ans+=ch,++p1,++p2;
        }
        //此时str1和str2可能还剩结尾一部分不属于公共序列的子串
        return ans+str1.substr(p1)+str2.substr(p2);
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值