Sliding Window Introduction
Feeling intimidated by coding interviews and uncertain about the types of questions you might face? If you’re short on time to practice data structure questions, you’re in luck. Data structures are a critical component of any coding interview, regardless of the position you’re applying for, and arrays are especially crucial.
In this blog, we’ve got you covered with 10 diverse array problems of varying difficulties that are commonly featured in interview questions. It’s essential to be well-equipped with various strategies, such as the two-pointer technique, sliding window, dynamic programming, Dutch national flag algorithm, subarray problems, and more.
We’ll address problems that incorporate different techniques so that, by the end of this blog, you’ll have knowledge of various optimal strategies to handle not only these problems, but also similar ones you may encounter in interviews. Let’s get started!
The problem involves finding the peak number within an array. A peak element is an element that has a value greater than its neighbors on both sides.
A straightforward way to solve this problem would be to traverse the array linearly and compare the current value with each neighbor. However, this method takes linear time, and you can speed up the process by incorporating binary search within the solution. Simply applying binary search, along with a check on neighboring elements, will efficiently produce the desired result.
Let’s code this solution and go through its implementation in detail.
Two pointers, left and right, are initialized to the starting and ending indices of the array, respectively.
In each iteration, the array is halved and the solution space is reduced using binary search.
The choice of the next half depends on where the peak element resides. This is obtained by first calculating the middle element i.e. mid.
If the mid is greater than the value on its right, the potential peak will be found within the left half of the array, and the right will then be reduced to mid’s index.
Otherwise, the mid will be found within the right half, so the left is updated to the index after mid.
Either the peak element (if found) or null (if not found) is returned.
Note: This approach returns the first peak element found if more than one exist.
The time complexity of this algorithm is O(log n), as it utilizes the binary search algorithm and halves the solution space each time. Because no extra space is used, the space complexity turns out to be O(1).
The task revolves around sorting an array that only consists of elements with values of 0, 1, or 2.
Due to its specific nature, you can apply an optimal solution that is quicker than a simple sorting algorithm. The Dutch national flag algorithm is the go-to algorithm for such a problem. It separates the array into three parts, each representing one of the values. Three pointers are used to iterate through the array and swap elements among these parts according to their values.
Let's code the algorithm and see how it works!
Three pointers (low, mid, and high) are set to the start, and end of the array, respectively.
The array is traversed using the mid until it reaches or exceeds the high pointer.
If the value at the mid is 0, we swap elements at low and mid and increment both low and mid.
If the value at the mid is 1, we move the mid pointer forward.
If the value at mid is 2, we swap elements at the mid and high and decrement the high pointer.
The time complexity of this algorithm is O(n) as it is traversed once linearly. The space complexity is O(1), as no extra space is used.
The problem involves finding the missing number in an array containing integers from 1 to n. Simply put, the array contains all numbers from 1 to n except one, and we have to find the missing value.
An efficient approach to solve this problem is to calculate the sum of integers from 1 to n using the formula:
On the other hand, we compute the sum of the given array. The difference between these two sums will be the missing number as that missing number will not be present in the sum of the array.
Let's begin coding!
The size variable is initialized to be one more than the length of the array, since the array needs to contain all numbers from 1 to n except one.
Next, the formula calculates the sum of integers from 1 to n using the above-mentioned formula.
Then, arraySum is used to calculate the sum of the given array by iterating through each element and adding it.
The missing number is then obtained by finding the difference between the calculated sum, using the formula, and the array’s sum arraySum.
The time complexity of this algorithm is O(n) as it is traversed once linearly. The space complexity is O(1) as no extra space is used.
The task involves rotating an array to the right by a specified number of positions.
We can solve such a problem by first reversing an array so that the target elements are brought to the start of the array. Once that is done, to ensure the correct order, we reverse the two subarrays using k as a boundary, respectively.
The reverse method takes three parameters—the array arr, and the start and end indices—and reverses this portion of the array.
Then, rotateArray takes the array arr and the given value k, which shows the number of positions to rotate.
We ensure k does not exceed the size of the array using the modulo % operator.
The complete array is reversed, bringing the required number of elements to the front.
The first portion of the array, from index 0 to k - 1, is reversed.
The remaining portion of the array, from index k to the end n - 1, is reversed.
The time complexity of this algorithm is O(n), as the array is traversed linearly in the reverse function. The space complexity is O(1), as no extra space is used — only constant variables.
The task involves finding a
Such a problem requires the use of an approach called the sliding window. Read more about this approach in our course below.
The windowSum is created to store the sum of the current window and is initially initialized to zero.
The minWindow stores the minimum sum found overall after considering each window. It’s initially initialized to the maximum possible value so that it can be compared and updated during iterations.
The lastIndex saves the ending index of the subarray holding the sum.
We iterate through the array and update windowSum by adding the current element each time.
When the window size becomes equal to the given subArraySize, we update the windowSum if it is smaller than the current minimum minWindow.
To maintain the size of the window, the first element of the window is subtracted before moving to the next iteration.
At the end of the traversal, the start and end indices are printed. The start index can be found using lastIndex - subArraySize + 1.
The time complexity of this algorithm is O(n) due to a linear traversal. The space complexity is O(1) as no extra space is used.
The task here is to find a pair of elements in a given array that adds up to a specified sum given by the user. If there are two such numbers in the array that add up to the given value, they are returned. We assume that the array is sorted.
The solution involves utilizing a two-pointer approach. By initializing two pointers, left at the beginning and right at the end, this algorithm compares the sum of elements at these positions with our required sum.
The left pointer is initialized to the first element of the array.
The right pointer is initialized to the last element of the array.
The sum of elements at the left and right indices is computed and saved to sum.
If sum equals requiredSum, the pair is found and returned.
If sum is less than requiredSum, this means a larger sum is needed. The left pointer is therefore incremented to move toward the right.
If sum is greater than requiredSum, this means a smaller sum is needed. The right pointer is therefore decremented.
If we find a pair, it’s returned. If the pointers meet (i.e. the left >= right condition) without finding a pair, null is returned.
Let's dry run for a sum of 7 and an array [1, 2, 3, 4, 5, 6, 7, 8, 9].
The time complexity of this algorithm is O(n), as the array is traversed linearly. The space complexity is O(1), as no extra space is used.
This task involves an array containing integers and prompts us to move all the zeros present in the array to the left. Keep in mind that the order of the non-zero elements is to be maintained.
Due to its specific nature, you can apply an optimal solution that is quicker than a simple sorting algorithm. The Dutch national flag algorithm is the go-to algorithm for such a problem. It separates the array into three parts, each representing one of the values. Three pointers are used to iterate through the array and swap elements among these parts according to their values.
Let's code the algorithm and see how it works!
The optimal approach involves utilizing two pointers that keep track of zero and non-zero elements. In the first pass, the non-zero elements are identified and placed at the end of the array. In the second pass, the remaining positions to the left are filled with zeros, since we’ve already placed the non-zero elements at their correct position.
Two pointers are created and initialized to the end of the array readIdx and writeIdx.
First, the array is traversed from right to left using readIdx. If the element is non-zero, we move it to writeIdx. This ensures the non-zero elements are moved toward the right and the zeros are overwritten. We decrement both writeIdx and readIdx.
The remaining positions at the left indicate the number of zeros that were present in the array. These positions are then updated to zero. writeIdx is decremented until it reaches the beginning of the array.
The time complexity of this algorithm is O(n) as the array is traversed linearly. The space complexity is O(1) as no extra space is used.
Our task is to determine the contiguous subarray within a given array that contains the largest sum. A contiguous subarray is a subset of an array containing consecutive elements.
Two variables called maxEndingHere and maxSoFar are initialized with the first element’s value in the array.
The algorithm iterates through the array, starting from the second element.
At each step, we check whether or not to add the current element.
If adding the current element results in a larger sum, maxEndingHere is updated.
Otherwise, maxEndingHere is set to the current element (in case the current element was negative and resulted in a lesser sum).
If maxEndingHere surpasses maxSoFar, maxSoFar is updated to store the maximum subarray sum.
The time complexity of this algorithm is O(n), as it is traversed once linearly. The space complexity is O(1), as no extra space is used.
The problem revolves around finding a given number of largest values from an array of integers. Let’s say the number is 4, that means we have to find the four largest numbers from the array.
A priority queue can be employed to solve the k largest elements problem. This is done in the form of a min-heap. Initially, the first k elements of the array are inserted into the min-heap. This min-heap is responsible for maintaining k largest elements in the heap.
Let’s code the implementation and see how the min-heap works in detail.
A priority queue minHeap is initialized for the purpose of storing the k largest elements.
We add the first k elements of the array into the minHeap, regardless of their value, using the built-in offer() method.
The remaining array is iterated and each element is compared to the smallest element in the minHeap. The smallest element is obtained using peek().
If the current element being compared is larger than the smallest element in the min-heap, we remove the smallest element using poll() and insert the current value currentElement in minHeap.
After iterating through all elements, the minHeap now contains the k largest elements.
The algorithm iterates through the array once, and for each element it performs log(K) operations for insertion and removal in the min-heap. The time complexity turns out to be O(n * log(K)). The space complexity is O(K), as the min-heap stores at most k elements.
In this task we are given an array of possible coin values that we can use and a specific amount. We’re supposed to count the total number of ways we can make change for that amount using the given coins.
The coin change problem is a classic example of a dynamic programming problem and can be effectively solved using this approach. An array is used to keep track of the number of ways for each possible amount and, until the end of the traversal, we obtain the total ways for the final required amount.
An array dp is initialized to store the number of ways to make change for each amount.
The dp[0] is initially set to 1 since, for an amount of 0, there is only one way to make change, which is using no coins.
We use coin to represent the value of the current coin being considered.
The dp array is iterated, starting from the value of the current coin to the required amount.
We use i to represent the current amount being considered.
The dp[i] represents the number of ways to make change for this amount.
The dp[i] is updated for each i by adding the number of ways to make change using the current coin. This is done using dp[i] += dp[i - coin], which means for the current amount i, the number of ways to make change includes both the ways without using this coin (dp[i - coin]) and with using this coin (dp[i]).
At the end of the traversal, dp[i] will have the total number of ways to make change for each amount by considering the current coin. Ultimately, the array will be filled for all coins.
For an amount of 5, and possible coin values of 1, 2, and 3, a table like the one below is constructed.
The time complexity of this dynamic programming problem is given by O(n * amount), because for each coin we traverse each amount. The space complexity is O(amount), as we use an array to store the number of ways for each amount.
Congratulations! You’re now a master of array questions and can take on all similar questions employing these techniques! Here are a few other questions you can practice to further improve your skills:
What is the two-pointer technique?