[算法训练] 512周赛-①Q1-贪心②Q2-双指针③Q3-组合数学
512周赛-①Q1-贪心②Q2-双指针③Q3-组合数学
Q1-贪心
题目
给你两个非负整数 n 和 s。
返回满足下述条件的最大 整数:
- 最多有
n位数字。 - 其各位数字之和等于
s。
如果不存在这样的整数,则返回 -1。
贪心
① 字符串
最多填n个9,若s > 9n则无解
如果s = 0,则答案为0
否则,整数的十进制长度可以为n,从高到低填,如果s ≤ 9则这一位填s,其余为填0;如果s > 9,这一位填9,s-=9
class Solution {public: int largestInteger(int n, int s) { if(s > 9*n){ return -1; } if(s == 0){ return 0; } string ans(n,'0'); for(int i = 0;i<n;i++){ if(s <= 9){ ans[i] += s; break; } ans[i] = '9'; s -= 9; } return stoi(ans); }};② 数学
填 s//9个9
如果s%9>0,填s%9
最后填0
class Solution {public: int largestInteger(int n, int s) { if(s > 9*n){ return -1; } if(s == 0){ return 0; } int ans = (int) pow(10,s/9) - 1; if(s % 9){ ans = ans*10 + s%9; n--; } return ans * (int) pow(10,n - s/9); }};Q2-双指针
题目
给你两个二维整数数组 series1 和 series2。
两个序列中的每个元素都表示为 [timestamp, value],其中:
timestamp是表示时间的整数。value是表示该时间点对应值的整数。
每个数组都按照 timestamp 的 严格递增 顺序排列。
若某个序列中某个时间戳 缺失 ,且该序列中存在更晚的时间戳,则将该缺失时间戳的值设为下一个更晚时间戳对应的值。否则,该时间点的值视为 0。
聚合序列 通过以下方式构造:对于两个序列中出现过的每个时间戳,将两个序列在该时间戳对应的值相加。
返回聚合后的序列,格式为二维整数数组 [timestamp, summedValue],并按照 timestamp 严格递增 排序。
如果一个数组中的每个元素都严格大于前一个元素,则称该数组为严格递增 。
示例 1:
输入: series1 = [[1,3],[4,1]], series2 = [[2,2],[5,2]]
输出: [[1,5],[2,3],[4,3],[5,2]]
解释:
| 时间戳 | `series1` | `series2` | `summedValue` |
|---|---|---|---|
| 1 | 3 | 2 | 5 |
| 2 | 1 | 2 | 3 |
| 4 | 1 | 2 | 3 |
| 5 | 0 | 2 | 2 |
因此,聚合后的序列为 [[1, 5], [2, 3], [4, 3], [5, 2]]。
双指针
由于数组 series1和 series2已经分别按照时间戳升序排序,因此在遍历两个数组的过程中,可以定位到聚合序列中的当前时间戳并计算当前时间戳对应的值。
使用 i和 j分别表示数组 series1和 series2的下标,初始时 i=j=0。当两个数组中至少有一个数组没有遍历结束时,执行如下操作。如果两个数组都没有遍历结束,则取 series1[i] 和 series2[j] 这两组元素,两组元素的时间戳的较小值作为聚合序列中的当前时间戳,两组元素的值之和作为聚合序列中的当前时间戳对应的值。
计算聚合序列中的当前时间戳与对应的值之后,将较小时间戳对应的序列数组中的下标值增加 1,如果两个时间戳相等则两个数组中的下标值都增加 1。
如果只有一个数组没有遍历结束,则根据该数组的当前元素计算聚合序列中的当前时间戳与对应的值。
class Solution: def aggregateTimeSeries(self, series1: list[list[int]], series2: list[list[int]]) -> list[list[int]]: ans = [] n,m = len(series1),len(series2) i = j = 0 while i < n and j < m: t1,t2 = series1[i][0],series2[j][0] s = series1[i][1] + series2[j][1] if t1 < t2: ans.append([t1,s]) i += 1 elif t1 > t2: ans.append([t2,s]) j += 1 else: ans.append([t1,s]) i += 1 j += 1 ans += series1[i:] ans += series2[j:] return ansclass Solution {public: vector<vector<int>> aggregateTimeSeries(vector<vector<int>>& series1, vector<vector<int>>& series2) { vector<vector<int>> ans; int n = series1.size(); int m = series2.size(); int i = 0; int j = 0; while(i < n && j < m){ int t1 = series1[i][0],t2 = series2[j][0]; int sum = series1[i][1] + series2[j][1]; if(t1 < t2){ ans.push_back({t1,sum}); i++; } else if(t1 > t2){ ans.push_back({t2,sum}); j++; } else{ ans.push_back({t1,sum}); i++; j++; } } ans.insert(ans.end(),series1.begin() + i,series1.end()); ans.insert(ans.end(),series2.begin() + j,series2.end()); return ans; }};Q3-组合数学
题目
给你两个正整数 n 和 k。
一个有效序列 是一个由 k 个正整数组成的序列,满足以下条件:
- 序列中所有整数的和 等于
n。 - 序列中所有整数的乘积 是偶数 。
返回有效序列的数量。由于答案可能很大,请将其对 109 + 7 取余 后返回。
如果两个序列在任何下标处不同,则认为它们是不同 的序列。例如,[1, 1, 2] 和 [1, 2, 1] 被认为是不同的序列。
组合数学
乘积为偶数 ⟺ 序列中至少有一个偶数。
因为:奇数 × 奇数 = 奇数,任何数 × 偶数 = 偶数。
乘积为偶数的序列数 = 所有序列数 - 全为奇数的序列数
将 n 个相同的球排成一行,分成 k 份,每份至少 1 个。
在 n 个球之间的 (n-1) 个空隙中,选择 (k-1) 个位置插入隔板。
举例:n=5, k=3
球:● ● ● ● ●空隙: ↑ ↑ ↑ ↑选择 2 个空隙插入隔板
选位置 1 和 3:● | ● ● | ● ● → [1, 2, 2]
选位置 1 和 2:● | ● | ● ● ● → [1, 1, 3]
选位置 2 和 4:● ● | ● ● | ● → [2, 2, 1]
...共 C(4,2) = 6 种任意奇数可写成:(其中 )。
设序列为 。
必须是偶数,否则无解。
设 ,则 必须是非负整数。
将 m 个相同的球分给 k 个人,每人可以得 0 个(因为 )。
将 m 个球和 k-1 个隔板一起排列,总位置数 = m + k - 1,选择 k-1 个位置放隔板。
举例:n=5, k=3
- 将 1 个球分给 3 人:C(1+3-1, 2) = C(3, 2) = 3
三种分法(a₁, a₂, a₃):
| a₁ | a₂ | a₃ | 原序列 |
|---|---|---|---|
| 1 | 0 | 0 | \[3, 1, 1] |
| 0 | 1 | 0 | \[1, 3, 1] |
| 0 | 0 | 1 | \[1, 1, 3] |
class Solution: def countValidSequences(self, n: int, k: int) -> int: MOD = 10**9 +7 tot = comb(n-1,k-1) if (n - k)%2 == 0: m = (n - k)//2 odd = comb(m + k - 1,k-1) else: odd = 0 return (tot - odd)%MOD文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!