这是第二次正儿八经参加leetcode的周赛,与上一次参加相比,没什么长进,依旧是一道AC,一道差一些。
看到了一个大神,关注了一下,以下所有的非参赛时间的代码全部参考大神,权作学习。
leetcode第136场周赛赛题地址: https://leetcode-cn.com/contest/weekly-contest-136
困于环中的机器人
在无限的平面上,机器人最初位于 (0, 0) 处,面朝北方。机器人可以接受下列三条指令之一:
“G”:直走 1 个单位 “L”:左转 90 度 “R”:右转 90 度 机器人按顺序执行指令 instructions,并一直重复它们。
只有在平面中存在环使得机器人永远无法离开时,返回 true。否则,返回 false。
示例 1:
输入:“GGLLGG”
输出:true
解释: 机器人从 (0,0) 移动到 (0,2),转 180 度,然后回到 (0,0)。
重复这些指令,机器人将保持在以原点为中心,2 为半径的环中进行移动。
思路和参赛代码
这题想了一下,有一个初步的未经证明的想法:机器人走一个循环,如果下次走的方向和这次循环开始的方向不同,那么最终会走成一个圈,方向相同(除去回到原点这一种情况)则能够继续往远处走,可以回来
本场周赛,几乎所有的时间都在整第三题,这个题最后才会过来做的,代码非常挫。。。。可以忽略直接看后面的
class Solution {
public:
bool isRobotBounded(string instructions) {
int start = 0, end = 0;
int c[2] = {0, 0};
switch(instructions[0]) {
case 'G':
start = 0;
end = 0;
c[0]++;
break;
case 'L':
start = 1;
end = 1;
break;
case 'R':
start = 2;
end = 2;
break;
}
for (int i = 1; i < instructions.length(); i++) {
switch(instructions[i]) {
case 'G':
switch(end) {
case 0:
c[0]++;
break;
case 1:
c[1]++;
break;
case 2:
c[0]--;
break;
case 3:
c[1]--;
break;
}
break;
case 'L':
switch(end) {
case 0:
end = 3;
break;
case 1:
case 2:
case 3:
end -= 1;
break;
}
break;
case 'R':
switch(end) {
case 0:
case 1:
case 2:
end += 1;
break;
case 3:
end = 0;
break;
}
break;
}
}
switch(instructions[0]) {
case 'G':
break;
case 'L':
switch(end) {
case 0:
end = 3;
break;
case 1:
case 2:
case 3:
end -= 1;
break;
}
break;
case 'R':
switch(end) {
case 0:
case 1:
case 2:
end += 1;
break;
case 3:
end = 0;
break;
}
break;
}
if (c[0] == 0 && c[1] == 0) {
return true;
}
else if (end != start) {
// 换了方向,会被困死
return true;
}
else {
return false;
}
}
};
别人代码
我自己的肯定还能精简非常多,当时时间不够写的匆忙。因为不是很难,所以也懒得想了。看了一下大神的代码
class Solution {
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
public:
bool isRobotBounded(string instructions) {
int x=0,y=0,z=0,i,n=instructions.size();
for(i=0;i<n;i++)if(instructions[i]=='G')
{
x+=dx[z];
y+=dy[z];
}
else if(instructions[i]=='L')z=z+3&3;
else z=z+1&3;
if(!x&&!y)return 1;
return !!z;
}
};
思路是一样的,也是看一轮动作,回到原点则是true,否则看方向是否与原来相同,这就简洁很多了。
不邻接植花
题目
有 N 个花园,按从 1 到 N 标记。在每个花园中,你打算种下四种花之一。
paths[i] = [x, y] 描述了花园 x 到花园 y 的双向路径。
另外,没有花园有 3 条以上的路径可以进入或者离开。
你需要为每个花园选择一种花,使得通过路径相连的任何两个花园中的花的种类互不相同。
以数组形式返回选择的方案作为答案 answer,其中 answer[i] 为在第 (i+1) 个花园中种植的花的种类。花的种类用 1,2, 3, 4 表示。保证存在答案。
示例 1:
输入:N = 3, paths = [[1,2],[2,3],[3,1]]
输出:[1,2,3]
别人的解答
这题一开始看,感觉像图着色问题,图方面的暂时没有弄的打算,慢慢来,所以这题略过了。后来看了一下,发现好像可以回溯来做。 由于还有别的事情,也没有在结束后再来做这道题,直接上别人的代码吧
class Solution {
public:
vector<int> gardenNoAdj(int N, vector<vector<int>>& paths) {
vector<int> v[N];
for (auto e : paths)
{
v[e[0]-1].push_back(e[1]-1);
v[e[1]-1].push_back(e[0]-1);
}
vector<int> u(N);
for (int i = 0; i < N; ++ i)
{
if (u[i]) continue;
queue<int> Q;
Q.push(i);
u[i] = 1;
while (!Q.empty())
{
int x = Q.front();
Q.pop();
for (auto y : v[x])
{
if (u[y]) continue;
for (int c = 1; c <= 4; ++ c)
{
int flag = 0;
for (auto z : v[y])
if (u[z] == c) flag = 1;
if (!flag)
{
u[y] = c;
break;
}
}
Q.push(y);
}
}
}
return u;
}
};
分隔数组以得到最大和
题目
给出整数数组 A,将该数组分隔为长度最多为 K 的几个(连续)子数组。分隔完成后,每个子数组的中的值都会变为该子数组中的最大值。
返回给定数组完成分隔后的最大和。示例:
输入:A = [1,15,7,9,2,5,10], K = 3
输出:84
解释:A 变为 [15,15,15,9,10,10,10]提示:
1 <= K <= A.length <= 500
0 <= A[i] <= 10^6
思路和代码
这道题看上去是可以动态规划解的,我之前也是想好好补动态规划,所以几乎所有的时间都花在这上面了,但最后还是超时了。贴一下我的代码
class Solution {
public:
int dp[500][500];
int maxsum(int i, int j, int K, vector<int>& A) {
if (dp[i][j] != -1) {
return dp[i][j];
}
else if (i == j) {
dp[i][j] = A[i];
return dp[i][j];
}
else if(j - i + 1 <= K) {
int tmpmax = -1;
for (int m = i; m <= j; m++) {
tmpmax = max(tmpmax, A[m]);
}
dp[i][j] = tmpmax * (j-i+1);
return dp[i][j];
}
else {
int tmpmax = -1;
for (int m = 0; m < K, i+m+1<=j; m++) {
tmpmax = max(tmpmax, maxsum(i, i+m, K, A)+maxsum(i+m+1, j, K, A));
}
dp[i][j] = tmpmax;
return dp[i][j];
}
}
int maxSumAfterPartitioning(vector<int>& A, int K) {
memset(dp, -1, sizeof(dp));
return maxsum(0, A.size()-1, K, A);
}
};
再贴一下别人的代码
class Solution {
public:
int maxSumAfterPartitioning(vector<int>& A, int K) {
int m[505][505],n=A.size(),i,j,f[505];
for(i=0;i<n;i++)for(m[i+1][i+1]=A[i],j=i+1;j<n;j++)m[i+1][j+1]=max(m[i+1][j],A[j]);
memset(f,0,sizeof(f));
for(i=1;i<=n;i++)for(j=1;j<=i&&j<=K;j++)f[i]=max(f[i],f[i-j]+m[i-j+1][i]*j);
return f[n];
}
};
天壤之别,大写的服
最长重复子串
这题也没有看,直接上别人的解答:
https://leetcode-cn.com/discuss/forum.php?mod=viewthread&tid=906
以及 大神的代码:
class Solution {
public:
typedef long long ll;
int P=998244353,P1=1000000007,base=233,base1=666;
int h[100005],h1[100005],p[100005],p1[100005];
set<pair<int,int>> s;
string longestDupSubstring(string S) {
int n=S.size(),i,j,k,l,r,mid;
pair<int,int> o;
for(i=h[0]=0;i<n;i++)h[i+1]=((ll)h[i]*base+S[i])%P;
for(i=h1[0]=0;i<n;i++)h1[i+1]=((ll)h1[i]*base1+S[i])%P1;
for(i=p[0]=1;i<=n;i++)p[i]=(ll)p[i-1]*base%P;
for(i=p1[0]=1;i<=n;i++)p1[i]=(ll)p1[i-1]*base1%P1;
l=0;
r=n;
while(l+1<r)
{
mid=l+r>>1;
s.clear();
for(i=mid;i<=n;i++)
{
j=(h[i]+(ll)(P-h[i-mid])*p[mid])%P;
k=(h1[i]+(ll)(P1-h1[i-mid])*p1[mid])%P1;
o=make_pair(j,k);
if(s.find(o)==s.end())s.insert(o);
else break;
}
if(i>n)r=mid;
else l=mid;
}
s.clear();
for(i=l;i<=n;i++)
{
j=(h[i]+(ll)(P-h[i-l])*p[l])%P;
k=(h1[i]+(ll)(P1-h1[i-l])*p1[l])%P1;
o=make_pair(j,k);
if(s.find(o)==s.end())s.insert(o);
else break;
}
string ans="";
for(j=i-l;j<i;j++)ans+=S[j];
return ans;
}
};