Leetcode 74 & 240. Search a 2D Matrix I & II

Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:

  • Integers in each row are sorted from left to right.
  • The first integer of each row is greater than the last integer of the previous row.

For example,

Consider the following matrix:

[
  [1,   3,  5,  7],
  [10, 11, 16, 20],
  [23, 30, 34, 50]
]

Given target = 3, return true.

Analysis:

In a 2d array, we can consider it to be a 1d array. Then the mid value should be matrix[mid /col][mid%col]. This could be the key point for this problem. Then compare the value with target.

Time complexity: O(logmn)

Space complexity: O(1)

Below is the code:

public class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        // O(logmn) binary search
        
        // Corner case
        if(matrix == null || matrix.length == 0 
            || matrix[0] == null || matrix[0].length == 0) {
            return false;
        }
        
        int row = matrix.length;
        int col = matrix[0].length;
        int start = 0;
        int end = row * col - 1;
        
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            // Key point, the index is mid/col and mid%col
            int num = matrix[mid / col][mid % col];
            if (num == target) {
                return true;
            } else if (num < target) {
                start = mid;
            } else {
                end = mid;
            }
        }
        
        if (matrix[start / col][start % col] == target) {
            return true;
        } else if (matrix[end / col][end % col] == target) {
            return true;
        }
        
        return false;
    }
}

Followup:
Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:

Integers in each row are sorted in ascending from left to right.
Integers in each column are sorted in ascending from top to bottom.
For example,

Consider the following matrix:

[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
Given target = 5, return true.

Given target = 20, return false.

Analysis:
This problem is different from the first one. So in this case, we can’t use the first method to transfer from a 2d array to a 1d array.

However, we can still use the method similar to the binary search. Basically, we can go from the left bottom and consider it to be the mid value. Or we can go from the up right corner. In the code below, we choose from the left bottom.

If it equals to the target, we find it

If it’s larger than the target, we should move up

If it’s less than the target, we should move right

This is the trick part in this problem.

img_4165

Time complexity: O(m + n)

Space complexity: O(1)

The code is below:

public class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        // O(m + n) Similar to binary search
        
        // Corner case
        if (matrix == null || matrix.length == 0 ||
            matrix[0] == null || matrix[0].length == 0) {
                return false;
        }
        
        int row = matrix.length;
        int col = matrix[0].length;
        
        // Start from left bottom
        int x = row - 1;
        int y = 0;
        
        while (x >= 0 && y <= col - 1) {
            int num = matrix[x][y];
            
            if (num == target) {
                return true;
            } else if (num < target) {
                // Move right
                y++;
            } else {
                // Move up
                x--;
            }
        }
        
        return false;
    }
}

Leetcode 367. Valid Perfect Square

Given a positive integer num, write a function which returns True if num is a perfect square else False.

Note: Do not use any built-in library function such as sqrt.

Example 1:

Input: 16
Returns: True

Example 2:

Input: 14
Returns: False

Analysis:

This problem is the same as the problem of leetcode 69: https://codebysteven.wordpress.com/2016/09/08/leetcode-69-sqrtx/

Basically we can just change the return value from double to be boolean.

Time complexity: O(logn)

Space complexity: O(1)

Below is the code:

public class Solution {
    public boolean isPerfectSquare(int num) {
        // O(logn) binary search
        
        // Corner case
        if (num == 0 || num == 1) {
            return true;
        }
        
        long start = 1;
        long end = num;
        
        while (start + 1 < end) {
            long mid = start + (end - start) / 2;
            
            if (mid * mid == num) {
                return true;
            } else if (mid * mid < num) {
                start = mid;
            } else {
                end = mid;
            }
        }
        
        return false;
    }
}

Leetcode 69. Sqrt(x)

Implement int sqrt(int x).

Compute and return the square root of x.

Analysis:

To get the sqrt of x, we can use binary search to have a mid value. Then check the value of mid * mid. If it equals to x, then that’s the sqrt. Otherwise, keep going and make the mid larger to less.

Note in the code, we should make the start, mid and end to be long to avoid the precision losing.

Time complexity: O(logn)

Space complexity: O(1)

Below is the code:

public class Solution {
    public int mySqrt(int x) {
        // O(logn) binary search
        
        // Corner case
        if (x == 0 || x == 1) {
            return x;
        }
        
        // Make them to be long 
        long start = 1;
        long end = x;
        
        while (start + 1 < end) {
            long mid = start + (end - start) / 2;
            
            if (mid * mid <= x) {
                start = mid;
            } else {
                end = mid;
            }
        }
        
        if (start * start <= x) {
            return (int) start;
        } else if (end * end <= x) {
            return (int) end;
        }
        
        return 0;
    }
}

Leetcode 153 & 154. Find Minimum in Rotated Sorted Array I & II

Suppose a sorted array is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

Find the minimum element.

You may assume no duplicate exists in the array.

Analysis:

To find the min value in a rotated array, you may want to find the mid value. If the mid value is less than the end value, then move the end to the mid, otherwise, move the start to the mid value. Binary search.

Time complexity: O(logn)

Space complexity: O(1)

The code is below:

public class Solution {
    public int findMin(int[] nums) {
        // O(logn) binary search
        
        // Corner case
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        int start = 0; 
        int end = nums.length - 1;
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (nums[mid] < nums[end]) {
                end = mid;
            } else {
                start = mid;
            }
        }
        
        if (nums[start] <= nums[end]) {
            return nums[start];
        } else {
            return nums[end];
        }
        
    }
}

Follow up for “Find Minimum in Rotated Sorted Array”:
What if duplicates are allowed?

Would this affect the run-time complexity? How and why?

Analysis:

If duplicates allowed, then we can’t use binary search. Then brute force.

Below is the code:

public class Solution {
    public int findMin(int[] nums) {
        // O(n) 
        
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        int min = nums[0];
        
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] < min) {
                min = nums[i];
            }
        }
        
        return min;
    }
}

Leetcode 33 & 81. Search in Rotated Sorted Array I & II

Suppose a sorted array is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

You are given a target value to search. If found in the array return its index, otherwise return -1.

You may assume no duplicate exists in the array.

Analysis:

For rotated array, we must have figure to analysis it. Basically it falls into the following two cases: either the mid is larger than the end, or the mid is smaller than the end.

Then in each case, we can use binary search to find the target value. Note that, we should compare both the start, mid, end with the target.

img_4163

Time complexity: O(logn)

Space complexity: O(1)

Below is the code:

public class Solution {
    public int search(int[] nums, int target) {
        // O(logn) binary search
        
        // Corner case
        if (nums == null || nums.length == 0) {
            return -1;
        }
        
        int start = 0;
        int end = nums.length - 1;
        
        while (start + 1 < end) {             int mid = start + (end - start) / 2;             if (nums[mid] == target) {                 return mid;             }             // case 1             if (nums[mid] > nums[end]) {
                if (nums[mid] >= target && target >= nums[start]) {
                    end = mid;
                } else {
                    start = mid;
                }
            } else { // case 2
                if (nums[mid] <= target && target <= nums[end]) {
                    start = mid;
                } else {
                    end = mid;
                }
            }
        }
        
        if (nums[start] == target) {
            return start;
        } else if (nums[end] == target) {
            return end;
        }
        
        return -1;
    }
}

Follow up:
Follow up for “Search in Rotated Sorted Array”:
What if duplicates are allowed?

Would this affect the run-time complexity? How and why?

Write a function to determine if a given target is in the array.

Analysis:
In this case, if duplicates allowed, then we can not use binary search. So normally just use the brute force method.

The code is below:

public class Solution {
    public boolean search(int[] nums, int target) {
        // O(n) normally won't apprear during interview
        
        if(nums == null || nums.length == 0) {
            return false;
        }
        
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == target) {
                return true;
            }
        }
        
        return false;
    }
}

Leetcode 35. Search Insert Position

Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.

You may assume no duplicates in the array.

Here are few examples.
[1,3,5,6], 5 → 2
[1,3,5,6], 2 → 1
[1,3,5,6], 7 → 4
[1,3,5,6], 0 → 0

Analysis: the real purpose for this problem is to find the first number that is larger or equals to the target. If not found, then insert into the end, return end + 1

Time complexity: O(logn)

Space complexity: O(1)

The code is below:

public class Solution {
    public int searchInsert(int[] nums, int target) {
        // O(logn) binary search
        // To find the first number that's larger or equals to target
        // If not find, insert to the end, return end + 1
        
        // Corner case
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        int start = 0;
        int end = nums.length - 1;
        
        while (start + 1 < end) {             int mid = start + (end - start) / 2;             if (nums[mid] == target) {                 end = mid;             } else if (nums[mid] > target) {
                end = mid;
            } else {
                start = mid;
            }
        }
        
        if (nums[start] >= target) {
            return start;
        } else if (nums[end] >= target) {
            return end;
        } else {
            return end + 1; // not found, then insert it to the end
        }
    }
}

Leetcode 162. Find Peak Element

A peak element is an element that is greater than its neighbors.

Given an input array where num[i] ≠ num[i+1], find a peak element and return its index.

The array may contain multiple peaks, in that case return the index to any one of the peaks is fine.

You may imagine that num[-1] = num[n] = -∞.

For example, in array [1, 2, 3, 1], 3 is a peak element and your function should return the index number 2.

click to show spoilers.

Note:Your solution should be in logarithmic complexity.

 

Analysis:

To find the peak value and should be in log complexity. Then we think about binary search. To use binary search, we need to find the mid value. For the mid value, notice here the array is not sorted. So it only falls into the four cases like below:

img_4160

So we can divide the cases into three:

For case 2, mid > mid – 1, then let the start = mid

For case 4, mid > mid + 1, then let the end = mid

For case 1 & 3, we need to do nothing, or just se the end = mid

Time complexity: O(logn)

Space complexity: O(1)

The code is below:

public class Solution {
    public int findPeakElement(int[] nums) {
        // O(logn) binary search
        
        // Corner case
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        int start = 0;
        int end = nums.length - 1;
        
        while (start + 1 < end) {             int mid = start + (end - start) / 2;             // Check for ascending             if (nums[mid] > nums[mid - 1]) {
                start = mid;
            } else if (nums[mid] > nums[mid + 1]) { // check for descending 
                end = mid;
            } else {
                end = mid;
            }
        }
        
        // Check for peak value after getting the start and end
        if (nums[start] >= nums[end]) {
            return start;
        } else {
            return end;
        }
    }
}

Leetcode 374 Guess Number Higher or Lower

We are playing the Guess Game. The game is as follows:

I pick a number from 1 to n. You have to guess which number I picked.

Every time you guess wrong, I’ll tell you whether the number is higher or lower.

You call a pre-defined API guess(int num) which returns 3 possible results (-1, 1, or 0):

-1 : My number is lower
 1 : My number is higher
 0 : Congrats! You got it!

Example:

n = 10, I pick 6.

Return 6.

Analysis:

This problem is quite similar to the problem of Leetcode 278 First bad version. Both of them needs to find the target number in a sorted array. So in this case, we should use binary search.

Time Complexity: O(logn)

Space Complexity: O(1)

Below is the code:

/* The guess API is defined in the parent class GuessGame.
   @param num, your guess
   @return -1 if my number is lower, 1 if my number is higher, otherwise return 0
      int guess(int num); */

public class Solution extends GuessGame {
    public int guessNumber(int n) {
        // O(logn) binary search
        
        int start = 1;
        int end = n;
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            if (guess(mid) == 0) {
                return mid;
            } else if (guess(mid) == -1) {
                end = mid;
            } else {
                start = mid;
            }
        }
        
        if (guess(start) == 0) {
            return start;
        }
        
        if (guess(end) == 0) {
            return end;
        }
        
        return -1;
    }
}

Leetcode 33. Search in Rotated Sorted Array

Leetcode 33. Search in Rotated Sorted Array

Suppose a sorted array is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

You are given a target value to search. If found in the array return its index, otherwise return -1.

You may assume no duplicate exists in the array.

Analysis:

This is a common problem for Binary search. Here the array is not normally sorted, but rotated. But we can still use the Binary search to reduce the search range to half.

However, we need to add more conditions to check the range, we need to draw two lines here to help us understand the rotated sorted array.

Time complexity: O(logn)

Space complexity: O(1)

public class Solution {
    public int search(int[] nums, int target) {
        // Binary search O(logn)
        
        // Corner Case
        if (nums == null || nums.length == 0) {
            return -1;
        }
        
        int start = 0;
        int end = nums.length - 1;
        
        while (start + 1 < end) {
            int mid = start + (end - start) / 2;
            
            if (nums[mid] == target) {
                return mid;
            } 
            
            // One line
            if (nums[start] < nums[mid]) {
                if (nums[start] <= target && nums[mid] >= target) {
                    end = mid;
                } else {
                    start = mid;
                }
            } else { 
                // Another line
                if (nums[mid] <= target && nums[end] >= target) {
                    start = mid;
                } else {
                    end = mid;
                }
            }
        }
        
        if (nums[start] == target) {
            return start;
        }
        
        if (nums[end] == target) {
            return end;
        }
        
        return -1;
    }
}

 

Extention: 81. Search in Rotated Sorted Array II

Follow up for “Search in Rotated Sorted Array”:
What if duplicates are allowed?

Would this affect the run-time complexity? How and why?

Write a function to determine if a given target is in the array.

If we have duplicates in the array, could we use the binary search?

No!

Because we cannot cut the array to half, as the other half may contain the same number as previous half.

Leetcode 349 Intersection of Two Arrays 1 & 2

Leetcode 349 Intersection of Two Arrays 1

Given two arrays, write a function to compute their intersection.

Example:
Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2].

Note:

  • Each element in the result must be unique.
  • The result can be in any order.
Analysis:
This problem can be solved by different methods: Hashset and Two pointers
HashSet: no duplicate and no order
  • Put numbers in nums1 in a hashset, have another set for result
  • Go through nums2 and to see if set contains the number, if contains && resultset not contains, put it in the resultset
  • Transfer the numbers out to be the result int[]

Time complexity: O(n)

Space complexity: O(n)

Two pointers:

  • Sort both array
  • Two pointers start and if nums1[i] < nums2[j], i++; if nums[i] > nums2[j], j++; else add to a set and i++, j++
  • Transfer the numbers out to be the result int[]

Time complexity: O(nlogn)

Space complexity: O(n)

public class Solution {
    public int[] intersection(int[] nums1, int[] nums2) {
        // corner case
        if (nums1 == null || nums2 == null) {
            return null;
        }
        
        
        // Method 1 hashset O(n)
        HashSet set = new HashSet<>();
        HashSet resSet = new HashSet<>();
        
        for (int i = 0; i < nums1.length; i++) {
            set.add(nums1[i]);
        }
        
        
        for (int i = 0; i < nums2.length; i++) {
            if (set.contains(nums2[i]) && !resSet.contains(nums2[i])) {
                resSet.add(nums2[i]);
            }
        }
        
        
        int[] res = new int[resSet.size()];
        int index = 0;
        for (Integer i : resSet) {
            res[index++] = i;
        }
        
        return res;
        
        
        // Method 2 two pointers O(nlogn)
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        
        int i = 0;
        int j = 0;
        
        HashSet set = new HashSet<>();
        while (i < nums1.length && j < nums2.length) {
            if (nums1[i] < nums2[j]) {                 i++;             } else if (nums1[i] > nums2[j]) {
                j++;
            } else {
                set.add(nums1[i]);
                i++;
                j++;
            }
        }
        
        int[] res = new int[set.size()];
        int index = 0;
        for (Integer k : set) {
            res[index++] = k;
        }

        return res;
    }
    
}

 

 

350. Intersection of Two Arrays II

Given two arrays, write a function to compute their intersection.

Example:
Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2, 2].

Note:

  • Each element in the result should appear as many times as it shows in both arrays.
  • The result can be in any order.

Follow up:

  • What if the given array is already sorted? How would you optimize your algorithm?

  • What if nums1‘s size is small compared to nums2‘s size? Which algorithm is better?

  • What if elements of nums2 are stored on disk, and the memory is limited such that you cannot load all elements into the memory at once?

Analysis:

Similar to the above two pointers method, just allows duplicate, then change hashset to a list.

Time complexity: O(nlogn)

Space complexity: O(n)

public class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        // corner case
        if (nums1 == null || nums2 == null) {
            return null;
        }
        
        // Two pointers O(nlogn)
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        
        int i = 0;
        int j = 0;
        
        List list = new ArrayList<>();
        while (i < nums1.length && j < nums2.length) {
            if (nums1[i] < nums2[j]) {                 i++;             } else if (nums1[i] > nums2[j]) {
                j++;
            } else {
                list.add(nums1[i]);
                i++;
                j++;
            }
        }
        
        int[] res = new int[list.size()];
        int index = 0;
        for (Integer k : list) {
            res[index++] = k;
        }

        return res;

    }
}