【LeetCode】第 99 场双周赛
创始人
2024-05-28 21:30:55
0

1. 最小和分割

给你一个二维整数数组 ranges ,其中 ranges[i] = [starti, endi] 表示 starti 到 endi 之间(包括二者)的所有整数都包含在第 i 个区间中。

你需要将 ranges 分成 两个 组(可以为空),满足:

  • 每个区间只属于一个组。
  • 两个有 交集 的区间必须在 同一个 组内。

如果两个区间有至少 一个 公共整数,那么这两个区间是 有交集 的。

  • 比方说,区间 [1, 3] 和 [2, 5] 有交集,因为 2 和 3 在两个区间中都被包含。

请你返回将 ranges 划分成两个组的 总方案数 。由于答案可能很大,将它对 109 + 7 取余 后返回。

示例 1:

输入:ranges = [[6,10],[5,15]]
输出:2
解释:
两个区间有交集,所以它们必须在同一个组内。
所以有两种方案:
- 将两个区间都放在第 1 个组中。
- 将两个区间都放在第 2 个组中。

示例 2:

输入:ranges = [[1,3],[10,20],[2,5],[4,8]]
输出:4
解释:
区间 [1,3] 和 [2,5] 有交集,所以它们必须在同一个组中。
同理,区间 [2,5] 和 [4,8] 也有交集,所以它们也必须在同一个组中。
所以总共有 4 种分组方案:
- 所有区间都在第 1 组。
- 所有区间都在第 2 组。
- 区间 [1,3] ,[2,5] 和 [4,8] 在第 1 个组中,[10,20] 在第 2 个组中。
- 区间 [1,3] ,[2,5] 和 [4,8] 在第 2 个组中,[10,20] 在第 1 个组中。

提示:

  • 1 <= ranges.length <= 105
  • ranges[i].length == 2
  • 0 <= starti <= endi <= 109

思路:

        小数在高位,顺序组成两个数

代码:

(1)数字直接进行顺序组成

class Solution {
public:int splitNum(int num) {int ans;unordered_map mp;while(num>0){//存储num中的所有数int w = num%10;num/=10;mp[w]++;}int sum1 = 0;int sum2 = 0;for(int i = 0;i<10;i++){//num每位数必然在0-9范围内 顺序进行 小数在高位while(mp[i]>0){if(mp[i]%2){//mp[i]是奇数 sum1 = sum1*10+i;if(mp[i]-->1){//如果mp[i]>1 sum2进行添加位数sum2 = sum2*10+i;mp[i]--;}else{//或者向后寻找其他数for(int j=i+1;j<10;j++){if(mp[j]-->0){sum2 = sum2*10+j;break;} }}}else{//偶数sum1 = sum1*10+i;sum2 = sum2*10+i;mp[i]-=2;}}}ans = sum1+sum2;return ans;}
};

(2)字符串排序顺序组成

class Solution {
public:int splitNum(int num) {string s = to_string(num);sort(s.begin(), s.end());//顺序升序int a[2]{};//存储sum1 sum2for (int i = 0; i < s.length(); ++i)a[i % 2] = a[i % 2] * 10 + s[i] - '0'; // 按照奇偶下标分组组成整数return a[0] + a[1];}
};

2.统计染色格子数

有一个无穷大的二维网格图,一开始所有格子都未染色。给你一个正整数 n ,表示你需要执行以下步骤 n 分钟:

  • 第一分钟,将 任一 格子染成蓝色。
  • 之后的每一分钟,将与蓝色格子相邻的 所有 未染色格子染成蓝色。

下图分别是 1、2、3 分钟后的网格图。

请你返回 n 分钟之后 被染色的格子 数目。

示例 1:

输入:n = 1
输出:1
解释:1 分钟后,只有 1 个蓝色的格子,所以返回 1 。

示例 2:

输入:n = 2
输出:5
解释:2 分钟后,有 4 个在边缘的蓝色格子和 1 个在中间的蓝色格子,所以返回 5 。

提示:

  • 1 <= n <= 105

 思路:

数学规律:4*(1+2+3+n)

代码:

class Solution {
public:long long coloredCells(int n) {//4*(1+2+3+n)long long m =(long long)n;return (1+2*(m-1)*m);}
};

3. 统计将重叠区间合并成组的方案数

给你一个二维整数数组 ranges ,其中 ranges[i] = [starti, endi] 表示 starti 到 endi 之间(包括二者)的所有整数都包含在第 i 个区间中。

你需要将 ranges 分成 两个 组(可以为空),满足:

  • 每个区间只属于一个组。
  • 两个有 交集 的区间必须在 同一个 组内。

如果两个区间有至少 一个 公共整数,那么这两个区间是 有交集 的。

  • 比方说,区间 [1, 3] 和 [2, 5] 有交集,因为 2 和 3 在两个区间中都被包含。

请你返回将 ranges 划分成两个组的 总方案数 。由于答案可能很大,将它对 109 + 7 取余 后返回。

示例 1:

输入:ranges = [[6,10],[5,15]]
输出:2
解释:
两个区间有交集,所以它们必须在同一个组内。
所以有两种方案:
- 将两个区间都放在第 1 个组中。
- 将两个区间都放在第 2 个组中。

示例 2:

输入:ranges = [[1,3],[10,20],[2,5],[4,8]]
输出:4
解释:
区间 [1,3] 和 [2,5] 有交集,所以它们必须在同一个组中。
同理,区间 [2,5] 和 [4,8] 也有交集,所以它们也必须在同一个组中。
所以总共有 4 种分组方案:
- 所有区间都在第 1 组。
- 所有区间都在第 2 组。
- 区间 [1,3] ,[2,5] 和 [4,8] 在第 1 个组中,[10,20] 在第 2 个组中。
- 区间 [1,3] ,[2,5] 和 [4,8] 在第 2 个组中,[10,20] 在第 1 个组中。

提示:

  • 1 <= ranges.length <= 105
  • ranges[i].length == 2
  • 0 <= starti <= endi <= 109

思路:

(1)将二维数组进行升序,这样包含关系更加清晰明了

(2)记录max(集合右边最大值),因为已经排好序,直接看下一个集合左边是否包含即可

(3)可知最后总数为2^n%(1e9+7)

代码:

(1)我最开始解法:

class Solution {
public:int countWays(vector>& ranges) {//最后变成几个元素的二组全排列问题 return pow(2,sum);int sum = 0;sort(ranges.begin(),ranges.end(),[](const vector& a,const vector& b){return (a[0] < b[0]) || (a[0]==b[0]&& a[1]=ranges[i+1][0]){//如果包含集合 继续寻找包含关系,直至不包含跳出循环max=std::max(max,ranges[i+1][1]);while(++i= 1000000007) {ans %= 1000000007;}}return ans;}
};

(2)更改(直接看是否属于一个集合,不包含直接产生新的集合):

class Solution {
public:int countWays(vector>& ranges) {//最后变成几个元素的二组全排列问题 return pow(2,sum);int sum = 2;sort(ranges.begin(),ranges.end(),[](const vector& a,const vector& b){return (a[0] < b[0]) || (a[0]==b[0]&& a[1]max){//如果不包含 则产生新的集合sum=sum*2%mod;}max = std::max(max,i[1]);}return sum;}
};

4.统计可能的树根数目

Alice 有一棵 n 个节点的树,节点编号为 0 到 n - 1 。树用一个长度为 n - 1 的二维整数数组 edges 表示,其中 edges[i] = [ai, bi] ,表示树中节点 ai 和 bi 之间有一条边。

Alice 想要 Bob 找到这棵树的根。她允许 Bob 对这棵树进行若干次 猜测 。每一次猜测,Bob 做如下事情:

  • 选择两个 不相等 的整数 u 和 v ,且树中必须存在边 [u, v] 。
  • Bob 猜测树中 u 是 v 的 父节点 。

Bob 的猜测用二维整数数组 guesses 表示,其中 guesses[j] = [uj, vj] 表示 Bob 猜 uj 是 vj 的父节点。

Alice 非常懒,她不想逐个回答 Bob 的猜测,只告诉 Bob 这些猜测里面 至少 有 k 个猜测的结果为 true 。

给你二维整数数组 edges ,Bob 的所有猜测和整数 k ,请你返回可能成为树根的 节点数目 。如果没有这样的树,则返回 0

示例 1:

输入:edges = [[0,1],[1,2],[1,3],[4,2]], guesses = [[1,3],[0,1],[1,0],[2,4]], k = 3
输出:3
解释:
根为节点 0 ,正确的猜测为 [1,3], [0,1], [2,4]
根为节点 1 ,正确的猜测为 [1,3], [1,0], [2,4]
根为节点 2 ,正确的猜测为 [1,3], [1,0], [2,4]
根为节点 3 ,正确的猜测为 [1,0], [2,4]
根为节点 4 ,正确的猜测为 [1,3], [1,0]
节点 0 ,1 或 2 为根时,可以得到 3 个正确的猜测。

示例 2:

输入:edges = [[0,1],[1,2],[2,3],[3,4]], guesses = [[1,0],[3,4],[2,1],[3,2]], k = 1
输出:5
解释:
根为节点 0 ,正确的猜测为 [3,4]
根为节点 1 ,正确的猜测为 [1,0], [3,4]
根为节点 2 ,正确的猜测为 [1,0], [2,1], [3,4]
根为节点 3 ,正确的猜测为 [1,0], [2,1], [3,2], [3,4]
根为节点 4 ,正确的猜测为 [1,0], [2,1], [3,2]
任何节点为根,都至少有 1 个正确的猜测。

提示:

  • edges.length == n - 1
  • 2 <= n <= 105
  • 1 <= guesses.length <= 105
  • 0 <= ai, bi, uj, vj <= n - 1
  • ai != bi
  • uj != vj
  • edges 表示一棵有效的树。
  • guesses[j] 是树中的一条边。
  • 0 <= k <= guesses.length

思路:

 如果只求以 000 为根时的猜对次数 cnt0 ,那么把 guesses 转成哈希表,DFS 一次这棵树就可以算出来。

如果要枚举以每个点为根时的猜对次数,暴力做法就太慢了,怎么优化呢?

注意到,如果节点 x 和 y 之间有边,那么从「以 x 为根的树」变成「以 y 为根的树」,就只有 [x,y][x,y][x,y] 和 [y,x][y,x][y,x] 这两个猜测的正确性变了,其余猜测的正确性不变。

因此,从 0 出发,再次 DFS 这棵树,从节点 x 递归到节点 y 时:

如果有猜测 [x,y][x,y][x,y],那么猜对次数减一;
如果有猜测 [y,x][y,x][y,x],那么猜对次数加一。
DFS 的同时,统计猜对次数 ≥k 的节点个数,即为答案。

代码:

class Solution {private List[] g;private Set s = new HashSet<>();private int k, ans, cnt0;public int rootCount(int[][] edges, int[][] guesses, int k) {this.k = k;g = new ArrayList[edges.length + 1];Arrays.setAll(g, e -> new ArrayList<>());for (var e : edges) {int x = e[0], y = e[1];g[x].add(y);g[y].add(x); // 建图}for (var e : guesses) // guesses 转成哈希表s.add((long) e[0] << 32 | e[1]); // 两个 4 字节数压缩成一个 8 字节数dfs(0, -1);reroot(0, -1, cnt0);return ans;}private void dfs(int x, int fa) {for (var y : g[x])if (y != fa) {if (s.contains((long) x << 32 | y)) // 以 0 为根时,猜对了++cnt0;dfs(y, x);}}private void reroot(int x, int fa, int cnt) {if (cnt >= k) ++ans; // 此时 cnt 就是以 x 为根时的猜对次数for (var y : g[x])if (y != fa) {int c = cnt;if (s.contains((long) x << 32 | y)) --c; // 原来是对的,现在错了if (s.contains((long) y << 32 | x)) ++c; // 原来是错的,现在对了reroot(y, x, c);}}
}

相关内容

热门资讯

小学师德报告会的主持词 小学师德报告会的主持词各位领导,各位老师:  大家下午好!采撷着金秋十月的累累硕果,收藏着金秋十月的...
《像小强一样儿活着》的经典台... 《像小强一样儿活着》的经典台词  《像小强一样活着》改编自同名网络小说,是难得的本土电影。曾有影评家...
汇演主持词 汇演主持词  主持词要根据活动对象的不同去设置不同的主持词。在人们积极参与各种活动的今天,主持人在各...
联欢会主持词结束语 联欢会主持词结束语(通用6篇)  晚会开得就是否成功圆满与主持人的讲话有很大关系。下面小编整理的联欢...
幼儿园毕业晚会主持词 幼儿园毕业晚会主持词  主持人在台上表演的灵魂就表现在主持词中。时代不断在进步,司仪等是很多场合都需...
美剧经典台词 美剧精选经典台词  在快速变化和不断变革的今天,能够利用到台词的场合越来越多,台词是一种特殊的,也是...
朗诵会主持词 关于朗诵会主持词4篇  主持词要根据活动对象的不同去设置不同的主持词。在当下这个社会中,很多场合都需...
记者节晚会主持词 记者节晚会主持词  主持词是主持人在台上表演的灵魂之所在。随着社会一步步向前发展,主持词的实用频率越...
婚礼父亲致辞 婚礼父亲致辞(精选15篇)  在平凡的学习、工作、生活中,大家肯定对各类致辞都很熟悉吧,致辞具有“礼...
校园红歌赛的主持词 校园红歌赛的主持词  主持词是主持人在节目进行过程中用于串联节目的串联词。在现今人们越来越重视活动氛...
开业主持词开场白 开业主持词开场白  根据活动对象的不同,需要设置不同的主持词。在当今社会生活中,活动集会越来越多,主...
关于唱歌比赛主持词   主持词是指主持人在主持节目的过程中进行节目串联的串联词,一般由开场白、中间部分与结束语组成。以下...
动漫感人台词 动漫感人台词(通用175句)  台词可以刻画人物的性格,表现人物的感情,加强剧情的表现力。那些广为流...
最新年会主持词 最新年会主持词(精选11篇)  契合现场环境的主持词能给集会带来双倍的效果。在如今这个时代,主持人的...
新生文艺汇演主持词 新生文艺汇演主持词  主持词要根据活动对象的不同去设置不同的主持词。在当今社会生活中,各种集会的节目...
家长代表幼儿园毕业典礼主持词 家长代表幼儿园毕业典礼主持词  主持词是各种演出活动和集会中主持人串联节目的串联词。在人们积极参与各...
学校元旦晚会主持词开场白和结... 学校元旦晚会主持词开场白和结束语  2017年元旦晚会主持词怎么写?怎么开场比较好呢?结束语又该怎么...
毕业晚会致辞 毕业晚会致辞(精选18篇)  在学习、工作或生活中,大家都写过致辞吧,致辞要求风格的雅、俗、庄、谐要...
幼儿园六一节目串词 幼儿园六一节目串词红黄蓝幼第一文库网儿园节目串词主持人(师):亲爱的家长朋友们( ):敬爱的老师们(...
祝寿主持词 祝寿主持词  主持词要尽量增加文化内涵、寓教于乐,不断提高观众的文化知识和素养。在人们积极参与各种活...