K Divisible Elements Subarrays

medium trie array enumeration

Problem

Given an array nums and integers k and p, return the number of distinct subarrays that have at most k elements divisible by p. A subarray is a non-empty contiguous slice; two subarrays are distinct if they differ in length or in any position.

Inputnums = [2,3,3,2,2], k = 2, p = 2
Output11
Indices 0, 3, 4 are divisible by 2. There are 11 distinct subarrays with at most 2 such elements; [2,3,3,2,2] is excluded (3 divisible) and repeats like [2] count once.

def countDistinct(nums, k, p):
    root = {}              # trie root (dict of children)
    count = 0              # distinct subarrays = new trie nodes
    n = len(nums)
    for i in range(n):     # start each subarray at index i
        node = root
        div = 0            # count of elements divisible by p
        for j in range(i, n):
            if nums[j] % p == 0:
                div += 1
            if div > k:    # too many divisible: stop extending
                break
            if nums[j] not in node:
                node[nums[j]] = {}   # new path = new subarray
                count += 1
            node = node[nums[j]]
    return count
function countDistinct(nums, k, p) {
  const root = new Map();   // trie root
  let count = 0;            // distinct subarrays = new nodes
  const n = nums.length;
  for (let i = 0; i < n; i++) {   // start at index i
    let node = root;
    let div = 0;            // elements divisible by p so far
    for (let j = i; j < n; j++) {
      if (nums[j] % p === 0) div++;
      if (div > k) break;   // too many divisible: stop
      if (!node.has(nums[j])) {
        node.set(nums[j], new Map());  // new path = new subarray
        count++;
      }
      node = node.get(nums[j]);
    }
  }
  return count;
}
int countDistinct(int[] nums, int k, int p) {
    Map<Integer, Object> root = new HashMap<>();  // trie root
    int count = 0;          // distinct subarrays = new nodes
    int n = nums.length;
    for (int i = 0; i < n; i++) {   // start at index i
        Map<Integer, Object> node = root;
        int div = 0;        // elements divisible by p so far
        for (int j = i; j < n; j++) {
            if (nums[j] % p == 0) div++;
            if (div > k) break;     // too many divisible: stop
            if (!node.containsKey(nums[j])) {
                node.put(nums[j], new HashMap<Integer, Object>());
                count++;            // new path = new subarray
            }
            node = (Map<Integer, Object>) node.get(nums[j]);
        }
    }
    return count;
}
struct Node { unordered_map<int, Node*> nxt; };

int countDistinct(vector<int>& nums, int k, int p) {
    Node* root = new Node();   // trie root
    int count = 0;             // distinct subarrays = new nodes
    int n = nums.size();
    for (int i = 0; i < n; i++) {   // start at index i
        Node* node = root;
        int div = 0;           // elements divisible by p so far
        for (int j = i; j < n; j++) {
            if (nums[j] % p == 0) div++;
            if (div > k) break;        // too many divisible: stop
            if (!node->nxt.count(nums[j])) {
                node->nxt[nums[j]] = new Node();  // new subarray
                count++;
            }
            node = node->nxt[nums[j]];
        }
    }
    return count;
}
Time: O(n²) Space: O(n²)