JavaScript-算法-和(积)为k的子数组

和(积)为k的子数组

和为k的子数组

1. 问题描述
给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。
2.解题思路一

  1. 暴力破解,双重for循环
  2. 若和等于k,计数+1
    var subarraySum = function(nums, k) {
    var count = 0;
    for(var i = 0; i < nums.length; i++){
        let sum = 0;
        for(var j = i; j < nums.length; j++){
            sum += nums[j];
            if(sum == k) count++;
        }
    }
    return count;

};

3. 图解一
输入:nums = [1,7,8,-2], k = 8
输出: 2 , [1,7] 与 [8] 为两种。

ijsumk执行
000+18j++
010+1+78count++,j++
020+1+7+88j++
030+1+7+8-28j++
048i++
110+78j++
120+7+88j++
130+7+8-28j++
148i++
220+88count++,j++
230+8-28j++
248i++
330-28j++
348i++
448return count

4. 解题思路二

  1. 哈希表存储,前缀和,以及出现的次数
  2. 若在哈希表里找到前缀和-k的值,计数+1
  3. 前缀和出现在哈希表里,出现次数+1
  4. 前缀和不在哈希表里,设置哈希表
    var subarraySum = function(nums, k) {
    var mp = new Map();
    mp.set(0,1);
    var pre = 0;
    var count = 0;
    for(const num of nums){
        pre += num;
        if(mp.has(pre - k)) count += mp.get(pre - k);
        if(mp.has(pre)) mp.set(pre, mp.get(pre) + 1);
        else mp.set(pre, 1);
    }
    return count;

};

5. 图解二
输入:nums = [1,7,8,-2], k = 8
输出: 2 , [1,7] 与 [8] 为两种。

步骤初始1234
num178-2
pre00+10+1+70+1+7+80+1+7+8-2
pre-k01-88-816-814-8
count012
mp(0,1)[(0,1),(1,1)][(0,1),(1,1),(8,1)[(0,1),(1,1),(8,1),(16,1)][(0,1),(1,1),(8,1),(16,1),(14,1)]

连续的子数组和

1. 问题描述
给定一个包含 非负数 的数组和一个目标 整数 k ,编写一个函数来判断该数组是否含有连续的子数组,其大小至少为 2,且总和为 k 的倍数,即总和为 n * k ,其中 n 也是一个整数。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/continuous-subarray-sum

2. 解题思路

  1. 创建哈希表,存储前缀和mod k的余和下标
  2. 将前缀和mod k,取余
  3. 若下标值出现在哈希表中,说明取到子数组和为k或k的倍数
  4. 当前遍历值-下标值,若大于1,说明子数组大小至少为2
    var checkSubarraySum = function(nums, k) {
    var mp = new Map();
    mp.set(0, -1);//记录(前缀和,下标)
    var pre = 0;
    for(var i = 0; i < nums.length; i++){
       pre += nums[i];
       //前缀和取余,循环之后再次出现,表示取到了总和为k倍数的子数组
       const nk = k == 0 ? pre : pre % k;
       if(mp.has(nk)){
           //下标差值大于1,表示子数组大小至少为2
           if((i - mp.get(nk)) > 1) return true;
       } 
       else mp.set(nk, i);
    }
    return false;
};

3. 图解
输入:[23,2,4,6,7], k = 6
输出:True
解释:[2,4] 是一个大小为 2 的子数组,并且和为 6。

步骤初始123
i012
num[i]2324
pre00+230+23+20+23+2+4
nk0515
mp(0,-1)[(0,-1),(5,0)][(0,-1),(5,0),(1,1)][(0,-1),(5,0),(1,1)]
i-mp.get(nk)2 - 0 > 1

乘积小于k的子数组

1. 问题描述
给定一个正整数数组 nums。
找出该数组内乘积小于 k 的连续的子数组的个数。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/subarray-product-less-than-k

2. 解题思路一

  1. 双重for循环
  2. 乘积小于k,计数+1
    var numSubarrayProductLessThanK = function(nums, k) {
    var count = 0;
    for(var i = 0; i < nums.length; i++){
        var pre = 1;
        for(var j = i; j < nums.length; j++){
            pre *= nums[j];
            if(pre < k) count++;
        }
    }
    return count;

};

3. 图解一
输入: nums = [10,5,2,6], k = 100
输出: 8
解释: 8个乘积小于100的子数组分别为: [10], [5], [2], [6], [10,5], [5,2], [2,6], [5,2,6]。
需要注意的是 [10,5,2] 并不是乘积小于100的子数组。

轮数(ij)num[j]prekcount执行
00101*101000pre<k,count++,j++
0151*10*51001pre<k,count++,j++
0221*10*5*21002pre=k,j++
0361*10*5*2*61002pre>k,j++
041002i++
1151*51002pre<k,count++,j++
1221*5*21003pre<k,count++,j++
1361*5*2*61004pre<k,count++,j++
141005i++
2221*21005pre<k,count++,j++
2361*2*61006pre<k,count++,j++
241007i++
3361*61007pre<k,count++,j++
341008i++

2. 解题思路二

  1. 从数组左边开始滑动
  2. 依次向右进行乘积,若遇到乘积大于等于k,左指针就向右移
    var numSubarrayProductLessThanK = function(nums, k) {
    var count = 0;
    var pre = 1;
    var left = 0;
    if(k <= 1) return 0;
    for(right = 0; right < nums.length; right++){
        pre *= nums[right];
        while(pre >= k){
            pre /= nums[left];
            left++;
        }
        count += right - left + 1;
    }
    
    return count;

};

3. 图解二
输入: nums = [10,5,2,6], k = 100
输出: 8
解释: 8个乘积小于100的子数组分别为: [10], [5], [2], [6], [10,5], [5,2], [2,6], [5,2,6]。
需要注意的是 [10,5,2] 并不是乘积小于100的子数组。

0123执行
nums10526
right/leftcount=0-0+1=1,right++
leftrightcount=1+ 1-0+1=3,right++
leftrightpre=k,pre/num[left],left++
leftrightcount=3 + 2-1+1=5,right++
leftrightcount=5 + 3-1+1=8,right++
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值