暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Leetcode第260场周赛

fighting小王子 2021-09-26
176

今天周赛难度比上次(259场)难点儿。第一题常规签到,数据规模不大,做题的时候直接暴力过的,刚刚复盘重新写了个o(n)的代码;第二题前缀和,要注意思考什么情况下才是真正的"最大、最小";第三题直接模拟;第四题区间dp,注意利用好 "表达式结果最大值不会超过1000" 这个条件。


keywords:前缀和;模拟;区间dp


5881. 增量元素之间的最大差值


【题目描述】


【思路】

最大规模只有1000,两重循环查找可以过。也可以每次维护一个最小值,用当前值减去最小值来获取最大差,这样复杂度可降到o(n)。


【代码】

class Solution {
public:
int maximumDifference(vector<int>& nums) {
int minn=nums[0],ans=0;
for(int i=1;i<nums.size();i++)
{
minn=min(minn,nums[i]);
ans=max(nums[i]-minn,ans);
}
return ans==0?-1:ans;
}
};


5882. 网格游戏


【题目描述】


【思路】

第一个人的目的就是让第二个人的得分最小,第二个人则在第一个人清理过的网格中尽量多地捡分,这是一类题。之前没总结过,姑且在这记录一个不太成熟的总结。这类题首先要理解清楚二者的目的,然后关注第一个人清理过后,在这基础上第二个人有哪些选择。第一个人目的是要让第二个人可能的得分最小化,他宁可自己收获少些也要让第二个人得到的尽量少。

两个人均只能向右或者向下走,又由于网格只有两行,任何人往下走了一次后(出发点是左上角就只能往右走了,只能拐一次弯,所以有下面这个图:

第一人可能行走的路线图:橙色代表其路线。

第一个人走过的地方分数会被清零,还有分数的位置剩下两块,图中蓝色和绿色部分。第二个人以尽量多拿分的原则走,可以拿到蓝色或者绿色部分所有的分,但不能兼得(因为只能向右或向下走,前面已说明),所以每次第一个人处理过后,第二个人可获得的最大分数就是蓝色或者绿色部分的和。这里序列和显然前缀和是不错的选择。第一个人的拐点可以 0 - n-1任意一列处,所以枚举每一个位置,找到第二人可获得的最大分数的最小值即可,复杂度o(n)。


【代码】

const int N=100010;


class Solution {
public:
long long int sum[2][N];
long long gridGame(vector<vector<int>>& grid) {
memset(sum,0,sizeof sum);
int n=grid[0].size();
for(int i=1;i<=n;i++)
{
sum[0][i]=grid[0][i-1]+sum[0][i-1];
sum[1][i]=grid[1][i-1]+sum[1][i-1];
}
int id=-1;
long long maxn=1e10;
for(int i=1;i<=n;i++)
maxn=min(maxn,max(sum[1][i-1],sum[0][n]-sum[0][i]));
return maxn;
}
};


5883. 判断单词是否能放入填字游戏内


【题目描述】


【思路】
直接模拟,按行或者列来找合适的位置是比较正常的思路,但复杂度还需要考虑。扫描行、列,复杂度o(n*m),如果n、m均达到10^5,那这思路就不一定能过了,还好这里保证了n*m不会超过10*6,可以上手写代码了。


【代码】

class Solution {
public:
bool placeWordInCrossword(vector<vector<char>>& board, string word) {
int m = board.size(), n = board[0].size(), len = word.size();
string rword=word;
reverse(rword.begin(),rword.end());
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(board[i][j]=='#')
continue;
int k=j;
bool f1=true,f2=true;
for(j ; j<n && board[i][j]!='#' ; j++)
{
if(j-k >= len || (board[i][j]!=' ' && word[j-k]!=board[i][j]))
f1=false;
if(j-k >= len || (board[i][j]!=' ' && rword[j-k]!=board[i][j]))
f2=false;
}
if((f1==true || f2==true) && j-k == len) return true;
}
}
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
if(board[j][i]=='#')
continue;
int k=j;
bool f1=true,f2=true;
for(j ; j<m && board[j][i]!='#'; j++)
{
if(j-k >= len || (board[j][i]!=' ' && word[j-k]!=board[j][i]))
f1=false;
if(j-k >= len || (board[j][i]!=' ' && rword[j-k]!=board[j][i]))
f2=false;
}
if((f1==true || f2==true) && j-k == len) return true;
}
}
return false;
}
};


5884. 解出数学表达式的学生分数


【题目描述】


【思路】

首先,表达式求值借助一个栈很容易求出来。剩下的难点就在于如何找出计算顺序错误时的计算结果。对于一个串 xOy,O表示一个运算符,此处可以是'+' 或 '*',x,y可以是一个串也可以是一个数字。xOy串所有可能的运算结果可以由x和y串中所有可能结果通过O(乘或加)运算得到,这里动态规划的思路就显而易见了。具体对应哪种动态规划,可以一个个套。

用dp[i][j]记录s[i...j]这个子串的所有运算结果,状态转移前面已经描述了:


s[i]=='+'  ==>  dp[i][j]=dp[i][k-1]+dp[k+1][j]
s[i]=='*'  ==>  dp[i][j]=dp[i][k-1]*dp[k+1][j]

最后所有可能的结果记录于dp[0][n-1]中,运算结果不会超过1000,状态转移过程中超过1000的状态可以直接剪枝,降低复杂度。初始化时,dp[i][i]默认就是s[i],可根据dp[i][j]的定义理解。另外,还可以用一个数组将出现过的结果都记录一次,这样计算最后的得分时dp[0][n-1]中每个元素都可在o(1)时间内计算完毕。

【代码】
const int N=1010;


class Solution {
public:
int count[N];
int Right_ans(string s)
{
stack<int> stk;
stk.push(s[0]-'0');
for(int i=1;i<s.length();i+=2)
{
if(s[i]=='+')
stk.push(s[i+1]-'0');
else
{
stk.top() *= (s[i+1]-'0');
}
}
int sum=0;
while(!stk.empty())
{
sum += stk.top();
stk.pop();
}
return sum;
}
int scoreOfStudents(string s, vector<int>& answers) {
memset(count,0,sizeof count);
for(auto &x:answers)
count[x]++;

int right_ans=Right_ans(s);


int n=s.length();

unordered_set<int> dp[40][40];

for(int j=0;j<n;j++)
dp[j][j].insert(s[j]-'0');

for(int len=2; len<n; len+=2)
{
for(int i=0; i+len < n; i+=2)
{
int j=i+len;
for(int t=0; t < len; t+=2)
{
for(auto &x : dp[i][i+t])
{
for(auto &y : dp[i+t+2][j])
{
if(s[i+t+1]=='+')
{
if( x+y <= 1000)
dp[i][j].insert( x+y );
}
else
{
if( x*y <= 1000)
dp[i][j].insert( x*y );
}
}


}
}
}
}


int scores=5*count[right_ans];
for(auto &x : dp[0][n-1])
{
if(x!=right_ans) scores += 2*count[x];
}
return scores;
}
};


点我可留言噢~


文章转载自fighting小王子,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论