Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
You are given 2 integer arrays nums1 and nums2 of lengths n and m respectively. You are also given a positive integer k.
A pair (i, j) is called good if nums1[i] is divisible by nums2[j] * k (0 <= i <= n - 1, 0 <= j <= m - 1).
Return the total number of good pairs.
Example 1:
Input: nums1 = [1,3,4], nums2 = [1,3,4], k = 1
Output: 5
Explanation:
The 5 good pairs are(0, 0), (1, 0), (1, 1), (2, 0), and (2, 2).Example 2:
Input: nums1 = [1,2,4,12], nums2 = [2,4], k = 3
Output: 2
Explanation:
The 2 good pairs are (3, 0) and (3, 1).
Constraints:
1 <= n, m <= 1051 <= nums1[i], nums2[j] <= 1061 <= k <= 103Problem summary: You are given 2 integer arrays nums1 and nums2 of lengths n and m respectively. You are also given a positive integer k. A pair (i, j) is called good if nums1[i] is divisible by nums2[j] * k (0 <= i <= n - 1, 0 <= j <= m - 1). Return the total number of good pairs.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map
[1,3,4] [1,3,4] 1
[1,2,4,12] [2,4] 3
count-array-pairs-divisible-by-k)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #3164: Find the Number of Good Pairs II
class Solution {
public long numberOfPairs(int[] nums1, int[] nums2, int k) {
Map<Integer, Integer> cnt1 = new HashMap<>();
for (int x : nums1) {
if (x % k == 0) {
cnt1.merge(x / k, 1, Integer::sum);
}
}
if (cnt1.isEmpty()) {
return 0;
}
Map<Integer, Integer> cnt2 = new HashMap<>();
for (int x : nums2) {
cnt2.merge(x, 1, Integer::sum);
}
long ans = 0;
int mx = Collections.max(cnt1.keySet());
for (var e : cnt2.entrySet()) {
int x = e.getKey(), v = e.getValue();
int s = 0;
for (int y = x; y <= mx; y += x) {
s += cnt1.getOrDefault(y, 0);
}
ans += 1L * s * v;
}
return ans;
}
}
// Accepted solution for LeetCode #3164: Find the Number of Good Pairs II
func numberOfPairs(nums1 []int, nums2 []int, k int) (ans int64) {
cnt1 := map[int]int{}
for _, x := range nums1 {
if x%k == 0 {
cnt1[x/k]++
}
}
if len(cnt1) == 0 {
return 0
}
cnt2 := map[int]int{}
for _, x := range nums2 {
cnt2[x]++
}
mx := 0
for x := range cnt1 {
mx = max(mx, x)
}
for x, v := range cnt2 {
s := 0
for y := x; y <= mx; y += x {
s += cnt1[y]
}
ans += int64(s) * int64(v)
}
return
}
# Accepted solution for LeetCode #3164: Find the Number of Good Pairs II
class Solution:
def numberOfPairs(self, nums1: List[int], nums2: List[int], k: int) -> int:
cnt1 = Counter(x // k for x in nums1 if x % k == 0)
if not cnt1:
return 0
cnt2 = Counter(nums2)
ans = 0
mx = max(cnt1)
for x, v in cnt2.items():
s = sum(cnt1[y] for y in range(x, mx + 1, x))
ans += s * v
return ans
// Accepted solution for LeetCode #3164: Find the Number of Good Pairs II
/**
* [3164] Find the Number of Good Pairs II
*/
pub struct Solution {}
// submission codes start here
impl Solution {
pub fn number_of_pairs(nums1: Vec<i32>, nums2: Vec<i32>, k: i32) -> i64 {
use std::collections::HashMap;
let mut nums1_count = HashMap::with_capacity(nums1.len());
let mut nums1_max = 0;
for i in nums1 {
let entry = nums1_count.entry(i).or_insert(0);
*entry += 1;
nums1_max = nums1_max.max(i);
}
let mut nums2_count = HashMap::with_capacity(nums2.len());
for i in nums2 {
let entry = nums2_count.entry(i).or_insert(0);
*entry += 1;
}
let mut result = 0;
for (i, count) in nums2_count {
let mut value = i * k;
while value <= nums1_max {
if let Some(&count1) = nums1_count.get(&value) {
result += count1 * count;
}
value += i * k;
}
}
result
}
}
// submission codes end
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_3164() {
assert_eq!(
5,
Solution::number_of_pairs(vec![1, 3, 4], vec![1, 3, 4], 1)
);
assert_eq!(
2,
Solution::number_of_pairs(vec![1, 2, 4, 12], vec![2, 4], 3)
);
}
}
// Accepted solution for LeetCode #3164: Find the Number of Good Pairs II
function numberOfPairs(nums1: number[], nums2: number[], k: number): number {
const cnt1: Map<number, number> = new Map();
for (const x of nums1) {
if (x % k === 0) {
cnt1.set((x / k) | 0, (cnt1.get((x / k) | 0) || 0) + 1);
}
}
if (cnt1.size === 0) {
return 0;
}
const cnt2: Map<number, number> = new Map();
for (const x of nums2) {
cnt2.set(x, (cnt2.get(x) || 0) + 1);
}
const mx = Math.max(...cnt1.keys());
let ans = 0;
for (const [x, v] of cnt2) {
let s = 0;
for (let y = x; y <= mx; y += x) {
s += cnt1.get(y) || 0;
}
ans += s * v;
}
return ans;
}
Use this to step through a reusable interview workflow for this problem.
Two nested loops check every pair or subarray. The outer loop fixes a starting point, the inner loop extends or searches. For n elements this gives up to n²/2 operations. No extra space, but the quadratic time is prohibitive for large inputs.
Most array problems have an O(n²) brute force (nested loops) and an O(n) optimal (single pass with clever state tracking). The key is identifying what information to maintain as you scan: a running max, a prefix sum, a hash map of seen values, or two pointers.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Zero-count keys stay in map and break distinct/count constraints.
Usually fails on: Window/map size checks are consistently off by one.
Fix: Delete keys when count reaches zero.