当前位置: 面试刷题>> 通用子数组个数 (经典算法题500道)


题目描述补充

题目:通用子数组个数

给定两个整数数组 nums1nums2,以及一个整数 k。我们称 nums1 的一个子数组 A 是“通用”的,如果子数组 A 的和能够通过重新排列(不一定保持原有顺序)nums2 的某个子数组 B 的元素来得到,且这两个子数组的长度相等。如果 A 的长度至少为 k,则称 A 为一个“合格”的通用子数组。

你需要计算 nums1 中所有“合格”的通用子数组的个数。

注意

  1. 子数组是数组中的一个连续部分。
  2. 两个数组的元素不一定都是正数或都是负数。
  3. 数组中的元素范围在 32 位有符号整数内。

示例

输入

  • nums1 = [1, 2, 3, 2, 1]
  • nums2 = [2, 3, 4]
  • k = 3

输出

  • 2

解释

  • [1, 2, 3] 是一个通用子数组,因为 nums2 中的 [2, 3] 子数组可以通过重新排列得到 [1, 2, 3] 的和(均为 6)。
  • [2, 1, 2] 也是一个通用子数组,因为 nums2 中的 [3, 2] 子数组可以通过重新排列得到 [2, 1, 2] 的和(均为 5)。

PHP 示例代码

function numSubarraysWithSumK($nums1, $nums2, $k) {
    $count = 0;
    $sums1 = array();
    $sums2 = array();
    
    // 计算 nums2 所有子数组的和及出现的次数
    helper($nums2, $sums2, 0, 0);
    
    $sum = 0;
    $prefixSums = array(0 => 1); // 用于记录 nums1 的前缀和及出现次数
    
    for ($i = 0; $i < count($nums1); $i++) {
        $sum += $nums1[$i];
        
        for ($j = $i; $j >= max(0, $i - $k + 1); $j--) {
            $target = $sum - ($j == 0 ? 0 : $prefixSums[$j-1]['sum']);
            if (isset($sums2[$target])) {
                $count += $sums2[$target];
            }
        }
        
        if (!isset($prefixSums[$sum])) {
            $prefixSums[$sum] = array('sum' => $sum, 'count' => 0);
        }
        $prefixSums[$sum]['count']++;
    }
    
    return $count;
}

// 辅助函数,计算 nums2 的所有子数组和及其出现次数
function helper(&$nums, &$sums, $start, $currentSum) {
    $sums[$currentSum] = isset($sums[$currentSum]) ? $sums[$currentSum] + 1 : 1;
    if ($start < count($nums)) {
        helper($nums, $sums, $start + 1, $currentSum + $nums[$start]);
    }
}

// 使用示例
$nums1 = [1, 2, 3, 2, 1];
$nums2 = [2, 3, 4];
$k = 3;
echo numSubarraysWithSumK($nums1, $nums2, $k); // 输出 2

注意:上述 PHP 示例代码为了简化,直接使用了递归辅助函数来计算 nums2 的所有子数组和,这在实际应用中可能效率不高,特别是对于大数据集。可以考虑使用更高效的算法,如前缀和加哈希表等。

对于 Python 和 JavaScript 的实现,基本思路相同,但语法和具体实现细节会有所不同。你可以在码小课网站上找到更多相关内容的分享,以学习不同编程语言的实现方法和优化技巧。

推荐面试题