Hello, reader ๐๐ฝ ! Welcome to day 23 of the series on Problem Solving. Through this series, I aim to pick up at least one question everyday and share my approach for solving it.
Today, I will be picking up LeetCode's daily challenge problem: 645. Set Mismatch.
๐ค Problem Statement
- Given an array of integers 1 to n, one of the numbers is missing and another appears twice.
- Find the number that occurs twice and the number that is missing and return them in the form of an array.
- E.g.:
nums = [1,2,2,4]
=>[2,3]
nums = [2,3,2]
=>[2,1]
๐ฌ Thought Process - Brute Force
- The straightforward and brute force approach would be to check for every occurrence of all the numbers from
1 to n
in the array. - We maintain a count for every number. If the count for a number is 2 that means it occurs twice.
- If the count for a number after the inner loop executes is 0, that means it's missing in the array.
๐ฉ๐ฝโ๐ป Solution - Brute Force
Below is the code for the brute force approach.
class Solution { public int[] findErrorNums(int[] nums) { if(nums == null || nums.length < 2) { return new int[0]; } int n = nums.length; int[] missing = new int[2]; for(int i = 1; i <= n; i++) { int count = 0; for(int j = 0; j < n; j++) { if(nums[j] == i) { count++; } if(count == 2) { missing[0] = i; if(missing[1] != 0) { return missing; } } } if(count == 0) { missing[1] = i; if(missing[0] != 0) { return missing; } } } return missing; } }
Time Complexity: O(n^2) - n = number of elements - We check the entire array for all numbers 1 to n Space Complexity: O(1)
๐ฌ Thought Process - Sorting
- We can sort the array so that the numbers that appears twice occur together. This way it's easy to find out the number appearing twice.
- And to find which number is missing we can figure out which number in the array satisfies
num[i] - num[i-1] > 1
, where0 <= i < n
. - For e.g.: if the numbers after sorting are:
[1,2,2,4]
then we can clearly see fori=3
,num[3] - num[2] > 1
. Hence the missing number is3
. - One edge case is when
n
is the missing number in the array. For e.g.: ifnums = [1,2,2]
, then 3 is missing in the array. - In such a case, we will fail to find an element where
nums[i] - nums[i-1] > 2
. In this case, once the loop terminates we will have to check if the last element in the array is not equal to n. If this is true, then update the missing number as n. - Let's look at the code now.
๐ฉ๐ฝโ๐ป Solution - Sorting
The code for the sorted approach is below.
class Solution { public int[] findErrorNums(int[] nums) { if(nums == null || nums.length < 2) { return new int[0]; } int n = nums.length; int[] missing = new int[2]; Arrays.sort(nums); for(int i = 0; i<n; i++) { int num = nums[i]; int prev = i > 0 ? nums[i-1] : 0; if(i > 0 && prev == num) { missing[0] = num; } else if(num > prev+1) { missing[1] = num-1; } } if(nums[n-1] != n) { missing[1] = n; } return missing; } }
Time Complexity: O(n logn) - n = number of elements - since we are sorting the array Space Complexity: O(1)
๐ฌ Thought Process - Hash Table
- To bring down the solution to
O(n)
, we can use a hash map that stores the number in the array and their frequency in key, value pairs. - Then we can iterate over all the numbers from
1 to n
to find both the missing number whose frequency is not in the map and the number that appears twice.
๐ฉ๐ฝโ๐ป Solution - Hash Table
Below is the code for the approach using hash map.
class Solution { public int[] findErrorNums(int[] nums) { if(nums == null || nums.length < 2) { return new int[0]; } int n = nums.length; int[] missing = new int[2]; Map<Integer, Integer> frequency = new HashMap(); for(int i = 0; i<n; i++) { int num = nums[i]; frequency.put(num, frequency.getOrDefault(num, 0) + 1); } for(int i = 1; i <= n; i++) { if(!frequency.containsKey(i)) { missing[1] = i; } else if(frequency.get(i) == 2) { missing[0] = i; } } return missing; } }
Time Complexity: O(n) - n = number of elements Space Complexity: O(n) - n = number of elements - we store the num and it's frequency in a map
๐ฌ Thought Process - Count Sort
- We can using
counting sort
to sort all the n numbers such that every numberi
appears at indexi-1
. - This way we will know which number is missing and that appears twice when the index and number doesn't match.
- The speciality is that this takes only
O(n)
and no extra space. - To visualise, let's take the following example:
nums = [8,7,3,5,3,6,1,4]
.
๐ฉ๐ฝโ๐ป Solution - Count Sort
Below is the code for the count sort approach.
class Solution { public int[] findErrorNums(int[] nums) { if(nums == null || nums.length < 2) { return new int[0]; } int n = nums.length; int[] missing = new int[2]; int i = 0; while(i < n) { int num = nums[i]; int index = num-1; if(nums[index] != num) { // update the index int temp = nums[index]; nums[i] = temp; nums[index] = num; } else { i++; } } i = 0; while(i < n) { int num = nums[i]; int index = num-1; if(num != i+1) { missing[0] = num; missing[1] = i+1; break; } i++; } return missing; } }
Time Complexity: O(n) - n = number of elements Space Complexity: O(1)
There's another solution that uses bitwise XOR as well. You can find it on LeetCode solution section.
- You can find the code for this question in the GitHub repo here: 645. Set Mismatch.
Conclusion
That's a wrap for today's problem. If you liked my explanation then please do drop a like/ comment. Also, please correct me if I've made any mistakes or if you want me to improve something!
Thank you for reading!