A.圆形赛道上经过次数最多的扇区
题目比较长,要认真读题。读懂后,不难发现其实只要求出开始位置和结束位置上所有的点就可以了,因为他们之间的点一定是走过最多的。
注意:起始位置可能不是1。
class Solution {
public:
vector<int> mostVisited(int n, vector<int>& rounds) {
vector<int> ans;
int l=rounds[0];
int r=rounds[rounds.size()-1];
while(1)
{
ans.push_back(l);
if(l==r)break;
l=l%n+1;
}
sort(ans.begin(),ans.end());
return ans;
}
};
B.你可以获得的最大硬币数目
由于每次都拿不到最大的,那么就每次拿第二大的就可以了,排序后遍历,然后记录下一共拿了多少个,拿完了就退出。
class Solution {
public:
int maxCoins(vector<int>& piles) {
int ans=0,cnt=0;
sort(piles.begin(),piles.end());
for(int i=piles.size()-2;i>=0;i-=2)
{
ans+=piles[i];
cnt++;
if(cnt==piles.size()/3)break;
}
return ans;
}
};
C.查找大小为 M 的最新分组
对于连续的一段 1 1 1,我们只需要知道它的起点和终点就可以了,那么我们用数组 a [ i ] a[i] a[i]表示以第 i i i个位置为结尾的 1 1 1的长度是多少,数组 b [ i ] b[i] b[i]表示以第 i i i个位置为起点的 1 1 1的长度是多少。接下来我们循环遍历 a r r arr arr,那么对于当前点 a r r [ i ] arr[i] arr[i]来说,通过加入这个 1 1 1连接两边形成的新的连续 1 1 1的长度就是 a [ a r r [ i ] − 1 ] + b [ a r r [ i ] + 1 ] + 1 a[arr[i]-1]+b[arr[i]+1]+1 a[arr[i]−1]+b[arr[i]+1]+1,这时再更新这个新的"连续1"的起点和终点的 a , b a,b a,b。但是这个题目问的是能否还有长度为 m m m的连续1,我们再开一个变量记录当前有几个长度为 m m m的连续1,循环中更新就可以了。
class Solution {
public:
int findLatestStep(vector<int>& arr, int m) {
int a[100005],b[100005],cnt=0;
memset(a,0,sizeof(a));//houzui
memset(b,0,sizeof(b));//qianzui
int ans=-1;
for(int i=0;i<arr.size();i++)
{
int c=a[arr[i]-1]+b[arr[i]+1]+1;
if(c==m)cnt++;
if(a[arr[i]-1]==m)cnt--;//原来的m个1消失了
if(b[arr[i]+1]==m)cnt--;//原来的m个1消失了
if(cnt)ans=i+1;
a[arr[i]+b[arr[i]+1]]=c;
b[arr[i]-a[arr[i]-1]]=c;
}
return ans;
}
};
D.石子游戏 V
DP,对于每一段区间 l , r l,r l,r,枚举中间分界点,取最大的结果即可,预处理前缀和来加速计算。
class Solution {
int sum[505];
int dp[505][505];
int dfs(int l,int r)
{
if(dp[l][r])
return dp[l][r];
for(int i=l;i<=r;i++)
{
int s=0;
int ll=sum[i]-sum[l-1];
int rr=sum[r]-sum[i];
if(ll>rr)
s=rr+dfs(i+1,r);
else if(ll<rr)
s=ll+dfs(l,i);
else
s=ll+max(dfs(i+1,r),dfs(l,i));
dp[l][r]=max(dp[l][r],s);
}
return dp[l][r];
}
public:
int stoneGameV(vector<int>& stoneValue) {
for(int i=0;i<stoneValue.size();i++)
sum[i+1]=sum[i]+stoneValue[i];
return dfs(1,stoneValue.size());
}
};