4月25日

第一题: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中。

考察点:

  1. 前缀和运用
  2. 模运算
  3. 哈希表优化时间复杂度
  4. 数字转化能力,(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值之后的和,这样可以正确计算进位数。

        同时为了方便头指针操作,我们创建一个哨兵节点,在返回时返回哨兵节点的下一位,即可返回答案链表。

考察点:

        数学运算与进位处理结合链表操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值