第一题
题目:
解法:说实话这道题建议出题人看看自己在说什么,首先n这个数据毫无意义,说白了就是通过两两时间相减找到耗时最大任务并且返回对应员工,对于时间一样都是最大的员工取id最小。
第二题
题目:
解法:这道题其实自己在纸上写一写也能找到规律,从灵神那里得到了一种规律,即关于差分数组和前缀和数组之间与初始数组之间的转化:
这里的差分指的是一种概念,即对于两两相邻的数进行某一种运算或规律,而前缀和运算则是对i
之前的数组中的所有数进行某种运算或规律的重复执行,这里pref
数组是一个前缀和数组(对到i
的数进行异或),所以我们想要得到原数组只要对pref
数组数组进行差分操作,即两两相邻异或即可。
第三题
题目:
解法:这道题主要是考察栈的思维,然后还加入了一个栈顶元素和后面最小元素的比较问题,我因为没想到怎么快速找到后面数据的最小字符超时了,运用灵神的思路时间复杂度可以降到O(n)
。
class Solution {
public:
string robotWithString(string s) {
string ans;
int cnt[26]{}, min = 0; // min 表示剩余最小字母,min=0代表剩余最小的是a
for (char c : s) ++cnt[c - 'a'];//用一个计数的数组来获取剩下字符串的最小值
stack<char> st;
for (char c : s) {
--cnt[c - 'a'];//遍历到的时候count--
while (min < 25 && cnt[min] == 0) ++min;//count数等于0说明在后面的字符中已经没有该字母了,剩下的是更大的,min++
st.push(c);
while (!st.empty() && st.top() - 'a' <= min) {
ans += st.top();
st.pop();
}
}
return ans;
}
};
第四题
题目:
解法:我自己第一时间直接无脑dfs了,结果不出所料超出时间限制捏
class Solution {
public:
int numberOfPaths(vector<vector<int>>& grid, int k) {
int ans=0;
int n=grid.size();
int m=grid[0].size();
function <void(int,int,int)> dfs = [&](int sum,int x,int y){
if(x==m-1 && y==n-1){
sum+=grid[y][x];
if(sum%k==0){
ans++;
return ;
}
}
else if(x>=m || y>=n){
return ;
}
else{
sum+=grid[y][x];
dfs(sum,x+1,y);
dfs(sum,x,y+1);
}
};
dfs(0,0,0);
return ans;
}
};
来看看正确的方法:
想要降低运算时间还是得用动态规划存储子问题答案,我的方法之所以超时是因为我保存的记忆化搜索是sum,这个值说白了每一条路都不一样,没有记录的意义。不妨设f[i][j][v]
为从(0,0)
出发到(i,j)
路径和模k得v的路径数总和,这样可以得到答案为f[m][n][0]
,对于一个点位(i,j),到这个位置时其路径和对于k的模是有意义的,首先这个变量和答案挂钩,其次因为是模,所以情况也就只有k种,记录到数组中可以被当做子问题来使用:
class Solution {
public:
int numberOfPaths(vector<vector<int>> &grid, int k) {
const int mod = 1e9 + 7;
int m = grid.size(), n = grid[0].size(), f[m + 1][n + 1][k];
memset(f, 0, sizeof(f));
f[0][1][0] = 1;
for (int i = 0; i < m; ++i)
for (int j = 0; j < n; ++j)
for (int v = 0; v < k; ++v)
f[i + 1][j + 1][(v + grid[i][j]) % k] = (f[i + 1][j][v] + f[i][j + 1][v]) % mod;
return f[m][n][0];
}
};
以上题解只是对灵神题解的总结,非原创捏1