第一题:Leetcode2845每日一题https://leetcode.cn/problems/count-of-interesting-subarrays/description/?envType=daily-question&envId=2025-04-25
代码:
class Solution {
public:
long long countInterestingSubarrays(vector<int>& nums, int modulo, int k) {
vector<int> sum,counting;
int n=nums.size();
long long ret=0;
//sum.push_back(nums[0]);
for(int i=0;i<n;i++){
counting.push_back(nums[i]%modulo==k);
if(i==0)sum.push_back(counting[i]);
else sum.push_back(sum[i-1]+counting[i]);
}
unordered_map<int,int> mood;
mood[0]=1;
for(int i=0;i<n;i++){
int target=(sum[i]-k)%modulo;
if(target<0)target+modulo;
ret += mood[target];
mood[sum[i] % modulo]++;
}
return ret;
}
};
解题思路:
题目要我们求有趣子数组数,并且nums.length<=10^5,因此我们不能使用双重循环暴力解题。
范围内满足count%modulo-k==0的子数组成为有趣子数组,count为区间内满足nums[i]%modulo-k==0的元素个数。求区间个数和,这与k倍区间题目相类似,所以我们尝试使用前缀和来解题。
创建动态数组sum存储count的前缀和。sum[i]即为从初始位置到i位置满足条件的元素个数,sum[i]-sum[j]即为j~i区间内满足条件的元素个数(左开右闭)。(sum[i] - sum[j]) % modulo == k实际上可以转化为sum[j] % modulo == (sum[i] - k) % modulo。因为k一定小于modulo,所以k%modulo==k。
为了快速得到该区间是否满足有趣子数组,创建哈希表mood,其键为sum[i]-k对modulo的模。其值为相同的模数。在做k倍区间时我们知道了,若两前缀和的模相等,那么用大区间-小区间,该区间的模就为0,符合题目条件。所以我们本题也可以充分运用这个思想。为了防止target小于0,给小于0的target加上modulo。
ret累加mood[target],如果此前无模为target对应值的区间,则ret会加上0,若存在,则target会累加。
注意,mood[0]要在循环开始前初始化为1,这是因为不符合条件的区间要出现两个才能相减得到模为0,而原本模就为0的区间本身就可以累加到ret中。
考察点:
- 前缀和运用
- 模运算
- 哈希表优化时间复杂度
- 数字转化能力,(sum[i] - sum[j]) % modulo == k转化为sum[j] % modulo == (sum[i] - k) % modulo。
第二题:Leetcode2https://leetcode.cn/problems/add-two-numbers/description/ 
代码:
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode* dummy = new ListNode(); // 虚拟头节点
ListNode* current = dummy;
int carry = 0;
while (l1 || l2 || carry) {
int sum = carry;
if (l1) {
sum += l1->val;
l1 = l1->next;
}
if (l2) {
sum += l2->val;
l2 = l2->next;
}
carry = sum / 10;
current->next = new ListNode(sum % 10);
current = current->next;
}
return dummy->next;
}
};
解题思路:
l1,l2逆序存储,也就是头节点记载为个位数。若我们分别遍历两节点将数字取出,可能会涉及字符串与整型的转换操作,因此我们可以寻找更简便的方法。
我们知道,进位运算是向更高位进位,而我们对所给链表顺序遍历时,恰好符合数字的进位顺序。因此,我们创建while循环,用carry表示进位数,若l1或l2不为空,或还能进位,则继续向答案链表中创建新链表。要求答案链表也逆序存储,只需将每轮sum模10后放入答案链表即可,这与我们顺推l1,l2链表时是相似的。
每次carry=sum/10,sum为每轮累加了上局carry(用初始化实现)、l1值、l2值之后的和,这样可以正确计算进位数。
同时为了方便头指针操作,我们创建一个哨兵节点,在返回时返回哨兵节点的下一位,即可返回答案链表。
考察点:
数学运算与进位处理结合链表操作