Skip to content

Hashing Problems


Problem 1 Pair Sum K

Given arr[N] and K, check if there exists a pair(i, j) such that,

arr[i] + arr[j] == K && i != j

Example

Let's say we have an array of 9 elements and K, where K is our target sum,

Index 0 1 2 3 4 5 6 7 8
Array 8 9 1 -2 4 5 11 -6 4

K = 6: arr[2] + arr[5] : such a pair exists
K = 22: does not exist
K = 8: arr[4] + arr[8]: such a pair exists

Hence if K = 6 or 8 the answer is true, for K = 22, it will be false.


Question

Check if there exists a pair(i, j) such that, arr[i] + arr[j] == K && i != j in the given array A = [3, 5, 1, 2, 1, 2] and K = 7.

Choices

  • true
  • false

Question

Check if there exists a pair(i, j) such that, arr[i] + arr[j] == K && i != j in the given array A = [3, 5, 1, 2, 1, 2] and K = 10.

Choices

  • true
  • false

Warning

Please take some time to think about the bruteforce approach on your own before reading further.....

Problem 1 Brute Force

Idea 1:

Iterate on all pairs(i, j) check if their sum == k

Example 2:

Take another example of arr[5]

Index 0 1 2 3 4
arr[5] 3 2 6 8 4

We can have following cases of pairs from an array of size 5

“”

  • Here, since we are not allowed to consider pairs where i == j these diagonal elements (marked in red) will not be considered.
  • Now, as you can see the upper (blue) and lower (yellow) triangles represent the same pairs (order of pair doesn't matter here) our program would work with either one of these triangular parts.

Now, considering upper triangle -

Observation:

i j loops from [i...(N - 1)]
0 [0..N-1]
1 [1..N-1]
2 [2..N-1]
3 [3..N-1]
4 -

Here for every index of i, j loops from i to N - 1

For an arr[i], the target will be K-arr[i]

Pseudocode:

boolean checkPair(int arr[], int K) {

    int N = arr.length
    for (int i = 0; i < N; i++) {
        //target: K-arr[i]
        for (int j = i; j < N; j++) {
            if (arr[i] == K - arr[i]) {
                return true;
            }
        }
    }
    return false;
}

Complexity

Time Complexity: O(N^2)

Space Complexity: O(1)


Problem 1 Optimization with HashSet(Doesn't Work)

  • We can insert all elements in the set initially.
  • Now, iterate over every arr[i] and check if K-arr[i] is present in the set. If yes, return tue, else false.

“”


ISSUE: (Edge Case)

  • For even K value, say arr[i] is K/2 and only one occurrence of it is present.
  • Eg: A[] = {8, 9, 2, -1, 4, 5, 11, -6, 4}; K=4, we will end up considering 2(present at index 2) two times.

“”

We can see the above logic isn't working

Resolution:

We need not insert all elements into set at once. Rather only insert from [0, i - 1].


Problem 1 Optimization with HashSet(Works)

At ith index: Hashset should contain all the elements:[0...i - 1]

Let's take an example,

“”

  • Initially set is empty.
  • For every element at ith index, search for target (arr[i] - K) in set.
  • If found, it means it must have been previously inserted. If not, we'll insert arr[i], because in future if we'll find a pair, we'll be able to get the current element.

Let's take another example,

“”

Pseudocode:

boolean targetSum(int arr[], int K) {
    int N = arr.length;
    Hashset < int > bs;

    for (int i = 0; i < N; i++) {
        //target = K - arr[i]
        if (bs.contains(K - arr[i])) {
            return true;
        } else {
            bs.add(arr[i]);
        }
    }
    return false;
}

Question

Count pairs(i, j) such that, arr[i] + arr[j] == K && i != j in the given array. A = [3, 5, 1, 2, 1, 2] and K = 3.

Choices

  • 1
  • 2
  • 3
  • 4

In the given array A = [3, 5, 1, 2, 1, 2], pairs with sum = 3 are:

Pairs
{2, 3}
{2, 5}
{3, 4}

Problem 2 Count no. of pairs with sum K

Given an arr[n], count number of pairs such that

arr[i] + arr[j] = K && i != j

Example

Provided we have an arr[8] and K = 10, we have

Index 0 1 2 3 4 5 6 7
arr[8] 2 5 2 5 8 5 2 8

Pairs:

Pairs: 9
{0, 4}
{0, 7}
{1, 5}
{1, 3}
{2, 4}
{2, 7}
{3, 5}
{4, 6}
{6, 7}

Here (i, j) and (j, i) considered as same.

Warning

Please take some time to think about the optimised approach on your own before reading further.....

Optimised Approach(Same as in previous question)

  • Similar to our previous problem, we'll be searching for our target.
  • This time we also need to consider the frequency of how many times a particular element appeared, so we shall be maintianing a map.

“”

Pseudocode:

int countTargetSum(int arr[], int K) {
    int N = arr.length;
    Hashmap < int, int > hm;

    int c = 0;

    for (int i = 0; i < n; i++) {
        //target = K-arr[i]
        if (hm.contains(K - arr[i])) {
            c = c + hm[K - arr[i]] //freq of target = pairs
        }

        //insert arr[i]
        if (hm.contains(arr[i])) {
            hm[arr[i]]++;
        } else {
            hm.put(arr[i], 1);
        }
    }
    return c;
}

Complexity

Time Complexity: O(N)

Space Complexity: O(N)


Problem 3 Subarray with Sum K

Given an array arr[n] check if there exists a subarray with sum = K

Example:

We have the following array

Index 0 1 2 3 4 5 6 7 8
arr[7] 2 3 9 -4 1 5 6 2 5

Possible subarrays for the following values of K are,

  • k = 11: {2 3 9 -4 1}, {5, 6}
  • k = 10: {2 3 9 -4}
  • k = 15: {-4, 1, 5, 6, 2, 5}

Question

Check if there exist a subarray with sum = 110 in the given array?
A = [ 5, 10, 20, 100, 105 ]

Choices

  • No
  • YES

Approach

To get subarray sum for any subarray in constant time, we can create a prefix sum array.

Now, a subarray sum PF[i] - PF[j] should be equal to K

OR

a - b = K

We can fix a and get the corresponding pair for it, given by a - K

We can create a HashSet at the time of traversal simultaneously
Here, instead of creating prefix sum initially, we are calculating it while iterating through the array.

“”

Edge case:

If subarray from index 0 has sum = K.
Say, K = 10
a = 10, b = 10-10=0, now 0 won't be present in the array.
Please take below example:

“”

To resolve this, take 0 in the set initially.

“”

Pseudocode:

boolean targetSubarray(int arr[], int K) {
    int N = arr.length;
    long a = 0;

    //cumulative sum, long -> to avoid overflow
    HashSet < long > hs;
    hs.add(0);
    for (int i = 0; i < N; i++) {
        a = a + arr[i];

        //cumulative sum = target = a - k
        if (hs.contains(a - K)) {
            //subarray exists
            return true;
        } else {
            hs.add(a);
        }
    }
    return false;
}

Complexity

Time Complexity: O(N)

Space Complexity: O(N)


Problem 4 Distinct elements in every window of size K

Given an array of integers and a number, K. Find the count of distinct elements in every window of size K in the array.

Example

// Input:
Array = [1, 2, 1, 3, 4, 2, 3]
K = 4

// Output:
[3, 4, 4, 3]
  • In the first window [1, 2, 1, 3], there are 3 distinct elements: 1, 2, and 3.
  • In the second window [2, 1, 3, 4], there are 4 distinct elements: 2, 1, 3, and 4.
  • In the third window [1, 3, 4, 2], there are again 4 distinct elements: 1, 3, 4, and 2.
  • In the fourth window [3, 4, 2, 3], there are 3 distinct elements: 3, 4, and 2.

Warning

Please take some time to think about the solution approach on your own before reading further.....

Approach - Using HashSet

  • The code iterates through each possible window of size K in the given array.
  • For each window, a temporary HashSet (distinctSet) is created to store the distinct elements within that window.
  • Within the inner loop, the code adds each element of the window to the HashSet.
  • After processing the entire window, the size of the HashSet is calculated using distinctSet.size(), which represents the count of distinct elements.
  • The count is then added to the result list.
  • This process is repeated for all possible windows in the array.
  • The result list contains the count of distinct elements in each window

Pseudocode

//Pseudo code for 'countDistinctElements' function
function countDistinctElements(arr, k):
    result = empty list

    for i = 0 to length of arr - k:
        distinctSet = empty set

        for j = i to i + k - 1:
            add arr[j] to distinctSet

        add size of distinctSet to result

    return result

Complexity

Time Complexity: O((N-K+1) * K)

Considering the values of K as N/2, 1, and N.

When K = N/2:

If K is about half of N, then the expression simplifies to O((N/2 + 1) * N/2), which further simplifies to O((N^2 + N) / 4). In this case, the primary factor is N^2, leading to a time complexity of approximately O(N^2).

When K = 1:

When K is set to 1, the expression becomes O((N - 1 + 1) * 1), which straightforwardly simplifies to O(N). It's important to note that this doesn't align with the original statement of the time complexity being O(N^2).

When K = N:

If K is equal to N, then the expression becomes O((N - N + 1) * N), which further simplifies to O(N^2).

Space Complexity: O(K)


Problem 4 Sliding Window - Map

Sliding Window suggests to insert all elements of the first window in the set. Now slide the window, throw the prev element out and insert new adjacent element in the set.

But we can't use Set here, since it is possible that the element just thrown out may be present in the current window.

We will also need to maintain the frequency of elements, hence we will use Hashmap.

  • Maintain a HashMap to track the frequency of elements within the current subarray.
  • Initially, the algorithm populates the HashMap with the elements of the first subarray, counting distinct elements.
  • Then, as the window slides one step at a time:
    • The algorithm updates the HashMap by updating frequency of the element leaving the window and increasing frequency of the new element entering the window.
  • The distinct element count for each subarray is determined by the size of the HashMap.

Pseudocode

void subfreq(int ar[], int k) {
  int N = ar.length;

  HashMap < int, int > hm;

  // Step 1: Insert 1st subarray [0, k-1]
  for (int i = 0; i < k; i++) {
    //Increase frequecy by 1
    if (hm.contains(ar[i])) {
      int val = hm.get(ar[i]);
      hm.put(ar[i], val + 1);
    } else {
      hm.put(ar[i], 1);
    }

    print(hm.size());
  }

  //step 2: Iterate all other subarrays
  int s = 1, e = k;

  while (e < N) {
    //Remove ar[s-1]
    int val = hm[ar[s - 1]];
    hm[ar[s - 1]]--;

    if (hm.get[ar[s - 1]] == 0) {
      hm.remove(ar[s - 1]);
    }

    //add ar[e]
    if (hm.contains(ar[e])) {
      //Inc freq by 1
      int val = hm[ar[e]];
      hm[ar[e]]++;
    } else {
      hm.put(ar[e], 1);
    }

    print(hm.size());
    s++

  }
}

Complexity

Time Complexity: O(n)

Space Complexity: O(n)