[算法训练] 512周赛-①Q1-贪心②Q2-双指针③Q3-组合数学

1514 字
8 分钟
[算法训练] 512周赛-①Q1-贪心②Q2-双指针③Q3-组合数学

512周赛-①Q1-贪心②Q2-双指针③Q3-组合数学#

第 512 场周赛 - 力扣(LeetCode)

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`
1325
2123
4123
5022

因此,聚合后的序列为 [[1, 5], [2, 3], [4, 3], [5, 2]]

双指针#

由于数组 series1series2已经分别按照时间戳升序排序,因此在遍历两个数组的过程中,可以定位到聚合序列中的当前时间戳并计算当前时间戳对应的值。

使用 ij分别表示数组 series1series2的下标,初始时 i=j=0。当两个数组中至少有一个数组没有遍历结束时,执行如下操作。如果两个数组都没有遍历结束,则取 series1[i]series2[j] 这两组元素,两组元素的时间戳的较小值作为聚合序列中的当前时间戳,两组元素的值之和作为聚合序列中的当前时间戳对应的值。

计算聚合序列中的当前时间戳与对应的值之后,将较小时间戳对应的序列数组中的下标值增加 1,如果两个时间戳相等则两个数组中的下标值都增加 1。

如果只有一个数组没有遍历结束,则根据该数组的当前元素计算聚合序列中的当前时间戳与对应的值。

双指针-PY
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 ans
双指针-C++
class 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) 个位置插入隔板。

总数=Cn1k1\text{总数} = C_{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 种

任意奇数可写成:2a+12a + 1(其中 a0a \ge 0)。

设序列为 [2a1+1,2a2+1,,2ak+1][2a_1+1, 2a_2+1, \dots, 2a_k+1]

i=1k(2ai+1)=n2i=1kai+k=n2i=1kai=nki=1kai=nk2\sum_{i=1}^{k}(2a_i+1)=n\\2\sum_{i=1}^{k}a_i+k=n\\2\sum_{i=1}^{k}a_i=n-k\\\sum_{i=1}^{k}a_i=\frac{n-k}{2}

nkn - k 必须是偶数,否则无解。

m=nk2m = \frac{n - k}{2},则 mm 必须是非负整数

将 m 个相同的球分给 k 个人,每人可以得 0 个(因为 ai0a_i \ge 0)。

将 m 个球和 k-1 个隔板一起排列,总位置数 = m + k - 1,选择 k-1 个位置放隔板。

全奇数序列数=Cm+k1k1\text{全奇数序列数} = C_{m+k-1}^{k-1}

举例:n=5, k=3

  • m=532=1m = \frac{5-3}{2} = 1
  • 将 1 个球分给 3 人:C(1+3-1, 2) = C(3, 2) = 3

三种分法(a₁, a₂, a₃):

a₁a₂a₃原序列
100\[3, 1, 1]
010\[1, 3, 1]
001\[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

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

[算法训练] 512周赛-①Q1-贪心②Q2-双指针③Q3-组合数学
http://blog.7a7a68.xyz/posts/512周赛-q1-贪心q2-双指针-q3-组合数学/
作者
JulY
发布于
2026-07-26
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
JulY
愿你明日如绚丽之花.
公告
音乐
封面

音乐

暂未播放

0:00 0:00
暂无歌词
分类
标签
站点统计
文章
76
分类
4
标签
20
总字数
160,526
运行时长
0
最后活动
0 天前

目录