第一题:解密消息
思路:用关联容器使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;
}
};