力扣第300场周赛补题

第一题:解密消息

思路:用关联容器使key串中字母第一个出现的顺序和字符字典序建立对应联系。

class Solution {
public:
    string decodeMessage(string key, string message) {
        unordered_map<char,char> mp;//关联容器
        char c='a';
        for(int i=0;i<key.size();i++){
            if(key[i]!=' '&&!mp.count(key[i])) mp[key[i]]=c++;
        }//若字符串第i位不为空格且之前没出现过 就与给对应字母建立联系
        for(int i=0;i<message.size();i++){
            if(message[i]!=' ') message[i]=mp[message[i]];//替换
        }
        return message;
    }
};

第二题:螺旋矩阵 IV

思路:没什么思路就蛇形矩阵模板,参考acvv题库的756题

class Solution {
public:
    vector<vector<int>> spiralMatrix(int m, int n, ListNode* head) {
        vector<vector<int>> res(m,vector<int>(n));
        vector<int> tmp(m*n,-1);//初始化为-1
        int cur=0;
        while(head){
            tmp[cur++]=head->val;
            head=head->next;
        }//把链表中的数据存入tmp中 没数据的缺失部分自然就是-1
        int left = 0, right = n - 1, top = 0, bottom = m - 1;
        int k = 0;
        while (left <= right && top <= bottom) {
            for (int i = left ; i <= right; i ++) {
                res[top][i] = tmp[k ++];
            }
            for (int i = top + 1; i <= bottom; i ++) {
                res[i][right] = tmp[k ++];
            }
            for (int i = right - 1; i >= left && top < bottom; i --) {
                res[bottom][i] = tmp[k ++];
            }
            for (int i = bottom - 1; i > top && left < right; i --) {
                res[i][left] = tmp[k ++];
            }
            left ++, right --, top ++, bottom --;
        }
        return res;
    }
};

也可以使用偏移量来做,按照右下左上的顺序越界或遇到已经访问过的位置就转向

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> spiralMatrix(int m, int n, ListNode* head) {
        vector<vector<int>> res(m,vector<int>(n,-1));//给二维矩阵赋初值
        int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
        int x=0,y=0,d=1;
        for(int i=0;i<n*m&&head;i++){
            res[x][y]=head->val;
            int a=x+dx[d],b=y+dy[d];
            if(a<0||a>=m||b<0||b>=n||res[a][b]!=-1){//碰壁则转向
                d=(d+1)%4;//偏移
                a=x+dx[d],b=y+dy[d];
            }
            x=a,y=b;
            head=head->next;
        }
        return res;
    }
};

第三题:知道秘密的人数 

思路:用f[i][j]表示状态:第i天后保守秘密j天的人。状态O(n^2) 转移O(n),需要优化,发现转移时可以用前缀和预处理优化。

class Solution {
public:
    int peopleAwareOfSecret(int n, int delay, int forget) {
        const int MOD=1e9+7;
        vector<vector<int>> f(n+1,vector<int>(n+1));
        for(int i=1;i<=forget;i++) f[1][i]=1;//第i天后,保守秘密j天的人数
        for(int i=2;i<=n;i++){
            for(int j=1;j<=forget;j++){
                if(j==1) f[i][j]=(f[i-1][forget-1]-f[i-1][delay-1])%MOD;
                else f[i][j]=(f[i-1][j-1]-f[i-1][j-2])%MOD;//维护有前缀和 所得即为第i-1天后,保守秘密j-1天的人数
                f[i][j]=(f[i][j]+f[i][j-1])%MOD;//维护前缀和
            }
        }
        return (f[n][forget]+MOD)%MOD;
    }
};

第四题:网格图中递增路径的数目 

思路:滑雪模板变种,该题符合拓扑序,以(i,j)为起点的路线的集合为状态集合,状态转移为上下左右四个方位,参考acvv基础课第五讲动态规划最后一题

const int N=1010,MOD=1e9+7;
int f[N][N];//表示所有以(i,j)为起点的路线数目
class Solution {
public:
    int n,m;
    vector<vector<int>> g;
    int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
    int dp(int x,int y){
        int &v=f[x][y];
        if(v!=-1) return v;//已经计算过的直接返回避免重复计算
        v=1;//在自己方格长度为1
        for(int i=0;i<4;i++){
            int a=x+dx[i],b=y+dy[i];
            if(a>=0&&a<n&&b>=0&&b<m&&g[a][b]>g[x][y]){//不越界且要走到的位置比当前位置大
                v=(v+dp(a,b))%MOD;//以(x,y)为起点的路线数由其四周比其大的点转移而来
            }//记忆化搜索
        }
        return v;
    }
    int countPaths(vector<vector<int>>& grid) {
        n=grid.size(),m=grid[0].size();
        g=grid;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                f[i][j]=-1;
        int res=0;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                res=(res+dp(i,j))%MOD;
        return res;
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值