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

Leetcode第231场周赛

fighting小王子 2021-03-16
316

拖了两周了,终于把这场周赛补上了。这次第二、三题有一些难度,第三题卡了很久,在一个社区把我代码上传了后有大佬给我支持初始化爆int的问题,改了就AC了,所以来补坑了。


1784. 检查二进制字符串字段

题目描述:

给你一个二进制字符串 s ,该字符串 不含前导零 。

如果 s 最多包含 一个由连续的 '1' 组成的字段 ,返回 true 。否则,返回 false 。

样例:

输入:s = "1001"
输出:false
解释:字符串中的 1 没有形成一个连续字段。


输入:s = "110"
输出:true

数据约束:


  • 1 <= s.length <= 100

  • s[i]
    为 '0'
     或 '1'

  • s[0]
     为 '1'

AC代码:

bool checkOnesSegment(string s) {
int i=0,j=s.size()-1;
while(i<=j && s[i]=='0') i++;
while( i<=j && s[j]=='0') j--;
for(int k=i;k<=j;k++)
if(s[k]=='0') return false;
return true;
}


1785. 构成特定和需要添加的最少元素

题目描述:

给你一个整数数组 nums ,和两个整数 limit 与 goal 。数组 nums 有一条重要属性:abs(nums[i]) <= limit 。

返回使数组元素总和等于 goal 所需要向数组中添加的 最少元素数量 ,添加元素 不应改变 数组中 abs(nums[i]) <= limit 这一属性。

注意,如果 x >= 0 ,那么 abs(x) 等于 x ;否则,等于 -x 。

样例:

输入:nums = [1,-1,1], limit = 3, goal = -4
输出:2
解释:可以将 -2 和 -3 添加到数组中,数组的元素总和变为 1 - 1 + 1 - 2 - 3 = -4 。

数据约束:

1 <= nums.length <= 105

1 <= limit <= 10^6

-limit <= nums[i] <= limit

-10^9 <= goal <= 10^9

思路:

不妨记 sum = goal-数组和,先把sum取一下绝对值,因为题目只要求 abs(nums[i]) <= limit即可。而这道题的目的就是将正的sum不断减去0-limit中的一个数使sum=0,而需要减去的最少的数据个数就是最后的答案。很显然,这里用贪心思路,sum>limit时,每次都让sum减去limit就行,只有这样才能让减去的个数最小。所以需要减去的最小的个数就是 sum/limit上取整(上取整操作 上一篇文章提到过:(t+k-1/k) )。

AC代码:

int minElements(vector<int>& nums, int limit, int goal) {
long long sum=0;
// for(int i=0;i<nums.size();i++) sum+=nums[i];
      sum=accumulate(nums.begin(),nums.end(),0ll);//和函数
return (abs(goal-sum)+limit-1)/limit;
}


1786. 从第一个节点出发到最后一个节点的受限路径数

题目描述:

现有一个加权无向连通图。给你一个正整数 n ,表示图中有 n 个节点,并按从 1 到 n 给节点编号;另给你一个数组 edges ,其中每个 edges[i] = [ui, vi, weighti] 表示存在一条位于节点 ui 和 vi 之间的边,这条边的权重为 weighti 。

从节点 start 出发到节点 end 的路径是一个形如 [z0, z1, z2, ..., zk] 的节点序列,满足 z0 = start 、zk = end 且在所有符合 0 <= i <= k-1 的节点 zi 和 zi+1 之间存在一条边。

路径的距离定义为这条路径上所有边的权重总和。用 distanceToLastNode(x) 表示节点 n 和 x 之间路径的最短距离。受限路径 为满足 distanceToLastNode(zi) > distanceToLastNode(zi+1) 的一条路径,其中 0 <= i <= k-1 。

返回从节点 1 出发到节点 n 的 受限路径数 。由于数字可能很大,请返回对 109 + 7 取余 的结果。

样例:


输入:n = 5, edges = [[1,2,3],[1,3,3],[2,3,1],[1,4,2],[5,2,2],[3,5,1],[5,4,10]]
输出:3
解释:每个圆包含黑色的节点编号和蓝色的 distanceToLastNode 值。三条受限路径分别是:
1) 1 --> 2 --> 5
2) 1 --> 2 --> 3 --> 5
3) 1 --> 3 --> 5

数据约束:

1 <= n <= 2 * 104
n - 1 <= edges.length <= 4 * 104
edges[i].length == 3
1 <= ui, vi <= n
ui != vi
1 <= weighti <= 105
任意两个节点之间至多存在一条边
任意两个节点之间至少存在一条路径

思路:

最短路+dp。首先求n号节点到每一个节点的最短路,单源最短路,直接dijkstra算法就行。比赛时有的人用spfa写的也过了,但是后面去测试就过不了了,spfa平均时间复杂度是o(n),应该是后面数据加强了,2000的测试点过不了。朴素dijkstra算法估计也不一定能过,最好用优化的。然后是求受限路径数,dp。设f(i)为从i号节点到n号节点的受限路径数,则若i节点可以到j节点,且满足受限条件,则f(i)+=f(j)。

AC代码:

using PII=pair<long long ,long long>;
class Solution {
public:
const long long INF=1e10,MOD=1e9+7;
    //这里无穷大之前习惯性设置为0x3f3f3f3f,
    // 会出现爆int错误,导致2000的测试点过不了,注意一下
vector<vector<PII>> g;
vector<long long> d;
vector<int> f;
vector<bool> st;
int countRestrictedPaths(int n, vector<vector<int>>& edges) {
g.resize(n+1);d.resize(n+1,INF);f.resize(n+1,0);st.resize(n+1,false);
for(auto& e:edges)
{
int a=e[0],b=e[1],c=e[2];
g[a].push_back({b,c});
g[b].push_back({a,c});
}
d[n]=0;
priority_queue<PII,vector<PII>,greater<PII>> heap;
heap.push({0,n});
while(heap.size())
{
PII t=heap.top();
heap.pop();
long long distance=t.first;
int v=t.second;
if(st[v]) continue;
st[v]=true;
for(auto& e:g[v])
{
int j=e.first;
long long dis=e.second;
if(d[j]>distance+dis)
{
d[j]=dis+distance;
heap.push({d[j],j});
}
}
}
vector<PII> vs;
for(int i=1;i<=n;i++) {vs.push_back({d[i],i});}
sort(vs.begin(),vs.end());
f[n]=1;
for(auto& v:vs)
{
long long distance=v.first;
int u=v.second;
for(auto& p:g[u])
{
int j=p.first;
if(distance>d[j])
{
f[u]=(f[u]+f[j] )% MOD;
}
}
}
return f[1];
}
};


1787. 使所有区间的异或结果为零

题目描述:

给你一个整数数组 nums 和一个整数 k 。区间 [left, right](left <= right)的 异或结果 是对下标位于 left 和 right(包括 left 和 right )之间所有元素进行 XOR 运算的结果:nums[left] XOR nums[left+1] XOR ... XOR nums[right] 。

返回数组中 要更改的最小元素数 ,以使所有长度为 k 的区间异或结果等于零。

样例:

输入:nums = [1,2,0,3,0], k = 1
输出:3
解释:将数组 [1,2,0,3,0] 修改为 [0,0,0,0,0]


输入:nums = [3,4,5,2,1,7,3,4,7], k = 3
输出:3
解释:将数组 [3,4,5,2,1,7,3,4,7] 修改为 [3,4,7,3,4,7,3,4,7]

数据约束:

1 <= k <= nums.length <= 2000
0 <= nums[i] < 210

思路:

(字丑……我尽力了)

AC代码:

class Solution {
public:
const int M=1024; //nums[i] 异或 nums[j] 最大值为1023
const int INF=1e8; //无穷大
int s[1024];
int minChanges(vector<int>& nums, int k) {
int n=nums.size();
int m=(n+k-1)/k;
vector<vector<int>> f(k+1,vector<int>(M,INF));
f[0][0]=0;
int sum=0,minv=INF;
for(int i=1;i<=k;i++)
{
memset(s,0,sizeof s);
int len=m;
if(n%k && n%k < i) len--;
for(int j=0;j<len;j++)
s[nums[j*k+i-1]]++;
int maxv=0;
for(int j=0;j<1024;j++)
if(s[j])
maxv=max(maxv,s[j]);
sum+=len-maxv,minv=min(minv,maxv);
for(int j=0;j<1024;j++)
for(int u=0;u<len;u++)
{
int x=nums[u*k+i-1],cost=len-s[x];
f[i][j]=min(f[i][j],f[i-1][j^x]+cost);
}
}
return min(sum+minv,f[k][0]);
}
};
文章转载自fighting小王子,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论