第 72 场双周赛和第 281 场力扣周赛
第 72 场双周赛
5996. 统计数组中相等且可以被整除的数对
题目
给你一个下标从 0 开始长度为 n 的整数数组 nums 和一个整数 k ,请你返回满足 0 <= i < j < n ,nums[i] == nums[j] 且 (i * j) 能被 k 整除的数对 (i, j) 的 数目 。
示例 1:
输入:nums = [3,1,2,2,2,1,3], k = 2
输出:4
解释:
总共有 4 对数符合所有要求:
- nums[0] == nums[6] 且 0 * 6 == 0 ,能被 2 整除。
- nums[2] == nums[3] 且 2 * 3 == 6 ,能被 2 整除。
- nums[2] == nums[4] 且 2 * 4 == 8 ,能被 2 整除。
- nums[3] == nums[4] 且 3 * 4 == 12 ,能被 2 整除。
示例 2:
输入:nums = [1,2,3,4], k = 1
输出:0
解释:由于数组中没有重复数值,所以没有数对 (i,j) 符合所有要求。
提示:
1 <= nums.length <= 100
1 <= nums[i], k <= 100
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-equal-and-divisible-pairs-in-an-array
代码
遍历即可
class Solution {
public:
int countPairs(vector<int>& nums, int k) {
int ans=0;
for(int i=0; i < nums.size()-1; i++){
for(int j=i+1; j < nums.size(); j++){
if(nums[i]==nums[j] && i * j % k == 0){
ans ++;
}
}
}
return ans;
}
};
5997. 找到和为给定整数的三个连续整数
题目
给你一个整数 num ,请你返回三个连续的整数,它们的 和 为 num 。如果 num 无法被表示成三个连续整数的和,请你返回一个 空 数组。
示例 1:
输入:num = 33
输出:[10,11,12]
解释:33 可以表示为 10 + 11 + 12 = 33 。
10, 11, 12 是 3 个连续整数,所以返回 [10, 11, 12] 。
示例 2:
输入:num = 4
输出:[]
解释:没有办法将 4 表示成 3 个连续整数的和。
提示:
0 <= num <= 10^15
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-three-consecutive-integers-that-sum-to-a-given-number
代码
直接除3获取中间值,如果以中间值为基础的三维数之和为num返回3个值,否则返回空
class Solution {
public:
vector<long long> sumOfThree(long long num) {
long long mid = num / 3;
if(mid-1 + mid + mid + 1 == num){
return {mid-1, mid, mid+1};
}
return {};
}
};
5998. 拆分成最多数目的偶整数之和
题目
给你一个整数 finalSum 。请你将它拆分成若干个 互不相同 的偶整数之和,且拆分出来的偶整数数目 最多 。
比方说,给你 finalSum = 12 ,那么这些拆分是 符合要求 的(互不相同的偶整数且和为 finalSum):(2 + 10) ,(2 + 4 + 6) 和 (4 + 8) 。它们中,(2 + 4 + 6) 包含最多数目的整数。注意 finalSum 不能拆分成 (2 + 2 + 4 + 4) ,因为拆分出来的整数必须互不相同。
请你返回一个整数数组,表示将整数拆分成 最多 数目的偶整数数组。如果没有办法将 finalSum 进行拆分,请你返回一个 空 数组。你可以按 任意 顺序返回这些整数。
示例 1:
输入:finalSum = 12
输出:[2,4,6]
解释:以下是一些符合要求的拆分:(2 + 10),(2 + 4 + 6) 和 (4 + 8) 。
(2 + 4 + 6) 为最多数目的整数,数目为 3 ,所以我们返回 [2,4,6] 。
[2,6,4] ,[6,2,4] 等等也都是可行的解。
示例 2:
输入:finalSum = 7
输出:[]
解释:没有办法将 finalSum 进行拆分。
所以返回空数组。
示例 3:
输入:finalSum = 28
输出:[6,8,2,12]
解释:以下是一些符合要求的拆分:(2 + 26),(6 + 8 + 2 + 12) 和 (4 + 24) 。
(6 + 8 + 2 + 12) 有最多数目的整数,数目为 4 ,所以我们返回 [6,8,2,12] 。
[10,2,4,12] ,[6,2,4,16] 等等也都是可行的解。
提示:
1 <= finalSum <= 10^10
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-split-of-positive-even-integers
分析
如果num是奇数,那么他不可能被拆成若干个偶数的和,直接返回空。如果num是偶数则一定存在若干个偶数和为num,这时我们递增地对偶数进行深度优先搜索即可,注意这里只要找到可行解即可,所以我们一旦找到合适的情况即可退出。在代码中用flag来表示是否已找到合适的情况。
代码
class Solution {
public:
vector<long long> ans;
bool flag = false;
void dfs(long long num, long long start){
if(num < 0){
return;
}
if(num == 0){
flag = true;
return;
}
for(long long i=start; num && i <= num/2; i++){
ans.push_back(i * 2);
dfs(num - i * 2, i+1);
if(flag){
break;
}
ans.pop_back();
}
}
vector<long long> maximumEvenSplit(long long finalSum) {
if(finalSum % 2){
return {};
}
for(long long i=1; finalSum && i <= finalSum/2; i++){
ans.push_back(i * 2);
dfs(finalSum - i * 2, i+1);
if(flag){
break;
}
ans.pop_back();
}
return ans;
}
};
5999. 统计数组中好三元组数目
题目
给你两个下标从 0 开始且长度为 n 的整数数组 nums1 和 nums2 ,两者都是 [0, 1, …, n - 1] 的 排列 。
好三元组 指的是 3 个 互不相同 的值,且它们在数组 nums1 和 nums2 中出现顺序保持一致。换句话说,如果我们将 pos1v 记为值 v 在 nums1 中出现的位置,pos2v 为值 v 在 nums2 中的位置,那么一个好三元组定义为 0 <= x, y, z <= n - 1 ,且 pos1x < pos1y < pos1z 和 pos2x < pos2y < pos2z 都成立的 (x, y, z) 。
请你返回好三元组的 总数目 。
示例 1:
输入:nums1 = [2,0,1,3], nums2 = [0,1,2,3]
输出:1
解释:
总共有 4 个三元组 (x,y,z) 满足 pos1x < pos1y < pos1z ,分别是 (2,0,1) ,(2,0,3) ,(2,1,3) 和 (0,1,3) 。
这些三元组中,只有 (0,1,3) 满足 pos2x < pos2y < pos2z 。所以只有 1 个好三元组。
示例 2:
输入:nums1 = [4,0,1,3,2], nums2 = [4,1,0,2,3]
输出:4
解释:总共有 4 个好三元组 (4,0,3) ,(4,0,2) ,(4,1,3) 和 (4,1,2) 。
提示:
n == nums1.length == nums2.length
3 <= n <= 105
0 <= nums1[i], nums2[i] <= n - 1
nums1 和 nums2 是 [0, 1, …, n - 1] 的排列。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-good-triplets-in-an-array
分析
对nums1做映射,然后按照树状数组去做即可
代码
class Solution {
public:
vector<int> tree;
long long goodTriplets(vector<int>& nums1, vector<int>& nums2) {
int n = nums1.size();
vector<int> pos(n);
for (int i = 0; i < n; ++i) {
pos[nums2[i]] = i;
}
long long ans = 0;
tree.resize(n + 1);
// 只需要在 [1, n-1) 范围内枚举 pos1_y 即可
for (int i = 1; i < n - 1; ++i) {
update(pos[nums1[i - 1]] + 1);
int p = pos[nums1[i]];
int t = query(p);
ans += static_cast<long long>(t) * (n - i - p + t - 1);
}
return ans;
}
static int lowbit(int x) {
return x & (-x);
}
void update(int x) {
while (x < tree.size()) {
++tree[x];
x += lowbit(x);
}
}
int query(int x) {
int ans = 0;
while (x) {
ans += tree[x];
x -= lowbit(x);
}
return ans;
}
};
第 281 场力扣周赛
6012. 统计各位数字之和为偶数的整数个数
题目
给你一个正整数 num ,请你统计并返回 小于或等于 num 且各位数字之和为 偶数 的正整数的数目。
正整数的 各位数字之和 是其所有位上的对应数字相加的结果。
示例 1:
输入:num = 4
输出:2
解释:
只有 2 和 4 满足小于等于 4 且各位数字之和为偶数。
示例 2:
输入:num = 30
输出:14
解释:
只有 14 个整数满足小于等于 30 且各位数字之和为偶数,分别是:
2、4、6、8、11、13、15、17、19、20、22、24、26 和 28 。
提示:
1 <= num <= 1000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-integers-with-even-digit-sum
代码
遍历查询即可
class Solution {
public:
bool get(int n){
int c=0;
while(n){
c+=n % 10;
n /=10;
}
return c % 2 == 0;
}
int countEven(int num) {
int ans=0;
for(int i=2; i <= num; i++){
if(get(i)){
ans++;
}
}
return ans;
}
};
6013. 合并零之间的节点
给你一个链表的头节点 head ,该链表包含由 0 分隔开的一连串整数。链表的 开端 和 末尾 的节点都满足 Node.val == 0 。
对于每两个相邻的 0 ,请你将它们之间的所有节点合并成一个节点,其值是所有已合并节点的值之和。然后将所有 0 移除,修改后的链表不应该含有任何 0 。
返回修改后链表的头节点 head 。
示例 1:
输入:head = [0,3,1,0,4,5,2,0]
输出:[4,11]
解释:
上图表示输入的链表。修改后的链表包含:
- 标记为绿色的节点之和:3 + 1 = 4
- 标记为红色的节点之和:4 + 5 + 2 = 11
示例 2:
输入:head = [0,1,0,3,0,2,2,0]
输出:[1,3,4]
解释:
上图表示输入的链表。修改后的链表包含:
- 标记为绿色的节点之和:1 = 1
- 标记为红色的节点之和:3 = 3
- 标记为黄色的节点之和:2 + 2 = 4
提示:
列表中的节点数目在范围 [3, 2 * 105] 内
0 <= Node.val <= 1000
不 存在连续两个 Node.val == 0 的节点
链表的 开端 和 末尾 节点都满足 Node.val == 0
分析
链表遍历题,如果当前的结点不为空并且不为0相加,如果为0新建新的结点,并令结点值为0,注意要判断最后一个0结点的值的情况
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* mergeNodes(ListNode* head) {
ListNode* newhead = new ListNode;
if(!head){
return NULL;
}
while(head && head->val==0){
head = head->next;
}
if(!head){
return NULL;
}
ListNode* t=newhead, * last;
t->val = 0;
while(head){
if(head->val){
t->val += head->val;
}else{
ListNode* tmp = new ListNode;
tmp->val=0;
last=t;
t->next = tmp;
t = t->next;
}
head = head->next;
}
if(last && !t->val){
last->next = NULL;
}
return newhead;
}
};
6014. 构造限制重复的字符串
给你一个字符串 s 和一个整数 repeatLimit ,用 s 中的字符构造一个新字符串 repeatLimitedString ,使任何字母 连续 出现的次数都不超过 repeatLimit 次。你不必使用 s 中的全部字符。
返回 字典序最大的 repeatLimitedString 。
如果在字符串 a 和 b 不同的第一个位置,字符串 a 中的字母在字母表中出现时间比字符串 b 对应的字母晚,则认为字符串 a 比字符串 b 字典序更大 。如果字符串中前 min(a.length, b.length) 个字符都相同,那么较长的字符串字典序更大。
示例 1:
输入:s = “cczazcc”, repeatLimit = 3
输出:“zzcccac”
解释:使用 s 中的所有字符来构造 repeatLimitedString “zzcccac”。
字母 ‘a’ 连续出现至多 1 次。
字母 ‘c’ 连续出现至多 3 次。
字母 ‘z’ 连续出现至多 2 次。
因此,没有字母连续出现超过 repeatLimit 次,字符串是一个有效的 repeatLimitedString 。
该字符串是字典序最大的 repeatLimitedString ,所以返回 “zzcccac” 。
注意,尽管 “zzcccca” 字典序更大,但字母 ‘c’ 连续出现超过 3 次,所以它不是一个有效的 repeatLimitedString 。
示例 2:
输入:s = “aababab”, repeatLimit = 2
输出:“bbabaa”
解释:
使用 s 中的一些字符来构造 repeatLimitedString “bbabaa”。
字母 ‘a’ 连续出现至多 2 次。
字母 ‘b’ 连续出现至多 2 次。
因此,没有字母连续出现超过 repeatLimit 次,字符串是一个有效的 repeatLimitedString 。
该字符串是字典序最大的 repeatLimitedString ,所以返回 “bbabaa” 。
注意,尽管 “bbabaaa” 字典序更大,但字母 ‘a’ 连续出现超过 2 次,所以它不是一个有效的 repeatLimitedString 。
提示:
1 <= repeatLimit <= s.length <= 105
s 由小写英文字母组成
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/construct-string-with-repeat-limit
分析
可以按从大到小的字母将所有出现的字母进行排序,然后使用双指针,left指针表示当前所处的位置,right来表示当left位置不满足要求时可互换的位置
代码
class Solution {
public:
string repeatLimitedString(string s, int repeatLimit) {
unordered_map<int, int> freq;
for (char ch: s) {
++freq[ch];
}
string ans;
ans.reserve(s.size());
for (char ch = 'z'; ch >= 'a'; --ch) {
for (int i = 0; i < freq[ch]; ++i) {
ans.push_back(ch);
}
}
int cnt = 1;
for (int left = 1, right = 2; left < ans.size(); ++left) {
if (ans[left - 1] != ans[left]) {
cnt = 1;
}
else {
++cnt;
if (cnt > repeatLimit) {
right = max(right, left + 1);
while (right < ans.size() && ans[left] == ans[right]) {
++right;
}
if (right < s.size()) {
swap(ans[left], ans[right]);
cnt = 1;
}
else {
ans.erase(ans.begin() + left, ans.end());
break;
}
}
}
}
return ans;
}
};
6015. 统计可以被 K 整除的下标对数目
给你一个下标从 0 开始、长度为 n 的整数数组 nums 和一个整数 k ,返回满足下述条件的下标对 (i, j) 的数目:
0 <= i < j <= n - 1 且
nums[i] * nums[j] 能被 k 整除。
示例 1:
输入:nums = [1,2,3,4,5], k = 2
输出:7
解释:
共有 7 对下标的对应积可以被 2 整除:
(0, 1)、(0, 3)、(1, 2)、(1, 3)、(1, 4)、(2, 3) 和 (3, 4)
它们的积分别是 2、4、6、8、10、12 和 20 。
其他下标对,例如 (0, 2) 和 (2, 4) 的乘积分别是 3 和 15 ,都无法被 2 整除。
示例 2:
输入:nums = [1,2,3,4], k = 5
输出:0
解释:不存在对应积可以被 5 整除的下标对。
提示:
1 <= nums.length <= 10^5
1 <= nums[i], k <= 10^5
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-array-pairs-divisible-by-k
代码
class Solution {
public:
long long coutPairs(vector<int> &nums, int k) {
vector<int> divisors;
for (int d = 1; d * d <= k; ++d) { // 预处理 k 的所有因子
if (k % d == 0) {
divisors.push_back(d);
if (d * d < k) divisors.push_back(k / d);
}
}
long long ans = 0;
unordered_map<int, int> cnt;
for (int v : nums) {
ans += cnt[k / gcd(v, k)];
for (int d : divisors)
if (v % d == 0) ++cnt[d];
}
return ans;
}
};