Skip to content

2143. Choose Numbers From Two Arrays in Range 👍

  • Time: $O(2^n)$
  • Space: $O(2^n)$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
 public:
  int countSubranges(vector<int>& nums1, vector<int>& nums2) {
    constexpr int kMod = 1'000'000'007;
    int ans = 0;
    // {sum, count}, add if choose from nums1, minus if choose from nums2
    unordered_map<int, int> dp;

    for (int i = 0; i < nums1.size(); ++i) {
      // edge case: nums1[i] == nums2[i] == 0, so can't put them in the
      // initializer list.
      unordered_map<int, int> newDp;
      ++newDp[nums1[i]];
      ++newDp[-nums2[i]];

      for (const auto& [prevSum, count] : dp) {
        // Choose nums1[i].
        newDp[prevSum + nums1[i]] += count;
        newDp[prevSum + nums1[i]] %= kMod;
        // Choose nums2[i].
        newDp[prevSum - nums2[i]] += count;
        newDp[prevSum - nums2[i]] %= kMod;
      }

      dp = std::move(newDp);
      if (const auto it = dp.find(0); it != dp.cend()) {
        ans += it->second;
        ans %= kMod;
      }
    }

    return ans;
  }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class Solution {
  public int countSubranges(int[] nums1, int[] nums2) {
    final int kMod = 1_000_000_007;
    int ans = 0;
    // {sum, count}, add if choose from nums1, minus if choose from nums2
    Map<Integer, Integer> dp = new HashMap<>();

    for (int i = 0; i < nums1.length; ++i) {
      Map<Integer, Integer> newDp = new HashMap<>();
      // edge case: nums1[i] == nums2[i] == 0, so can't put them in the
      // initializer list.
      newDp.merge(nums1[i], 1, Integer::sum);
      newDp.merge(-nums2[i], 1, Integer::sum);

      for (final int prevSum : dp.keySet()) {
        final int count = dp.get(prevSum);
        final int chooseNums1 = prevSum + nums1[i];
        newDp.put(chooseNums1, (newDp.getOrDefault(chooseNums1, 0) + count) % kMod);
        final int chooseNums2 = prevSum - nums2[i];
        newDp.put(chooseNums2, (newDp.getOrDefault(chooseNums2, 0) + count) % kMod);
      }

      dp = newDp;
      if (dp.containsKey(0)) {
        ans += dp.get(0);
        ans %= kMod;
      }
    }

    return ans;
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution:
  def countSubranges(self, nums1: list[int], nums2: list[int]) -> int:
    kMod = 1_000_000_007
    ans = 0
    # {sum, count}, add if choose from nums1, minus if choose from nums2
    dp = collections.Counter()

    for a, b in zip(nums1, nums2):
      newDp = collections.Counter()
      newDp[a] += 1
      newDp[-b] += 1

      for prevSum, count in dp.items():
        # Choose nums1[i]
        newDp[prevSum + a] += count
        newDp[prevSum + a] %= kMod
        # Choose nums2[i]
        newDp[prevSum - b] += count
        newDp[prevSum - b] %= kMod

      dp = newDp
      ans += dp[0]
      ans %= kMod

    return ans