Leetcode 270. Closest Binary Search Tree Value

Given a non-empty binary search tree and a target value, find the value in the BST that is closest to the target.

Note:

  • Given target value is a floating point.

  • You are guaranteed to have only one unique value in the BST that is closest to the target.

Analysis:

Maintain a min value and update it with left and right .

Time complexity: O(logn)

Space complexity: O(1)

Code is below:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Solution {
    public int closestValue(TreeNode root, double target) {
        // O(logn)
        
        int min = root.val;
        
        while (root != null) {
            min = Math.abs(target - root.val) < Math.abs(target - min) ? root.val : min;
            root = root.val < target ? root.right : root.left;
        }
        
        return min;
    }
}

Leetcode 54 & 59. Spiral Matrix I & II

Given a matrix of m x n elements (m rows, n columns), return all elements of the matrix in spiral order.

For example,
Given the following matrix:

[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]

You should return [1,2,3,6,9,8,7,4,5].

Analysis:

Try to follow the steps from left to right, to bottom to left to up.

Note to consider the situations where row/col = 1

Time complexity: O(mn)

Space complexity: O(1)

The code is below:

public class Solution {
    public List spiralOrder(int[][] matrix) {
        // O(mn)
        List result = new ArrayList<>();
        
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return result;
        }
        
        int row = matrix.length;
        int col = matrix[0].length;
        int x = 0;
        int y = 0;
        
        while (row > 0 && col > 0) {
            // Only one row
            if (row == 1) {
                for (int i = 0; i < col; i++) {
                    result.add(matrix[x][y++]);
                }
                break;
            }
            
            // Only one col
            if (col == 1) {
                for (int i = 0; i < row; i++) {
                    result.add(matrix[x++][y]);
                }
                break;
            }
            
            // Move from top to right
            for (int i = 0; i < col - 1; i++) {
                result.add(matrix[x][y++]);
            }
            
            // Move from right to bottom
            for (int i = 0; i < row - 1; i++) {
                result.add(matrix[x++][y]);
            }
            
            // Move from bottem to lef
            for (int i = 0; i < col - 1; i++) {
                result.add(matrix[x][y--]);
            }
            
            // Move from left to top
            for (int i = 0; i < row - 1; i++) {
                result.add(matrix[x--][y]);
            }
            
            row -= 2;
            col -= 2;
            x++;
            y++;
        }
        return result;
    }
}

Followup:
Given an integer n, generate a square matrix filled with elements from 1 to n2 in spiral order.

For example,
Given n = 3,

You should return the following matrix:
[
[ 1, 2, 3 ],
[ 8, 9, 4 ],
[ 7, 6, 5 ]
]

Analysis:
Similar to the first question.

Time complexity: O(mn)

Space complexity: O(1)

Code is below:

public class Solution {
    public int[][] generateMatrix(int n) {
        int[][] matrix = new int[n][n];
        
        int num = 1;
        int x = 0;
        int y = 0;
        int row = n;
        int col = n;
        
        while (num <= n * n) {
            // one row/col
            if (row == 1 || col == 1) {
                matrix[x][y] = num;
                break;
            }
            
            // top to right
            for (int i = 0; i < col - 1; i++, num++) {
                matrix[x][y++] = num;
            }
            
            // right to bottom
            for (int i = 0; i < row - 1; i++, num++) {
                matrix[x++][y] = num;
            }
            
            // bottom to left
            for (int i = 0; i < col - 1; i++, num++) {
                matrix[x][y--] = num;
            }
            
            // left to top
            for (int i = 0; i < row - 1; i++, num++) {
                matrix[x--][y] = num;
            }
            
            row -= 2;
            col -= 2;
            x++;
            y++;
        }
        
        return matrix;
    }
}

Leetcode 15, 16 & 259. 3Sum 3Sum Closest & 3Sum Smaller

Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note: The solution set must not contain duplicate triplets.

For example, given array S = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

Analysis:

It’s very similar to the two sum with sorted array. Basically we need to sort the array, then use two pointers method to get the result.

Note: if we encounter duplicates, then we need to skip them and continue.

Time complexity: O(n^2)

Space complexity: O(n)

Below is the code:

public class Solution {
    public List<List> threeSum(int[] nums) {
        // Two pointers O(n^2) O(n)
        // Sort the array firstly, then use two pointers
        
        List<List> result = new ArrayList<>();
        if (nums == null || nums.length < 3) {
            return result;
        }
        
        Arrays.sort(nums);
        
        for (int i = 0; i < nums.length - 2; i++) {
            // To skip duplicates, like [0, 0, 0, 0]
            if (i != 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            
            // Two sum two pointers below
            int left = i + 1;
            int right = nums.length - 1;
            
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                
                if (sum == 0) {
                    List temp = new ArrayList<>();
                    temp.add(nums[i]);
                    temp.add(nums[left]);
                    temp.add(nums[right]);
                    result.add(temp);
                    left++;
                    right--;
                    
                    //To skip the duplicates
                    while (left < right && nums[left] == nums[left - 1]) {
                        left++;
                    }
                    
                    while (left < right && nums[right] == nums[right + 1]) {
                        right--;
                    }
                } else if (sum < 0) {
                    left++;
                } else {
                    right--;
                }
            }
        }
        
        return result;
    }
}

Followup:

Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.

    For example, given array S = {-1 2 1 -4}, and target = 1.

    The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).

Analysis:

The only difference here is to have a value of closest, we can initialize it to be the first three values then update it.

Time complexity: O(n^2)

Space complexity: O(1)

The code is below:

public class Solution {
    public int threeSumClosest(int[] nums, int target) {
        // Two pointers O(n^2) O(1)
        
        if (nums == null || nums.length < 3) {
            return 0;
        }
        
        Arrays.sort(nums);
        int closest = nums[0] + nums[1] + nums[2];
        
        for (int i = 0; i < nums.length - 2; i++) {
            // To skip duplicates, like 0, 0, 0, 0
            if (i != 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            
            int left = i + 1;
            int right = nums.length - 1;
            
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                if (Math.abs(sum - target) < Math.abs(closest - target)) {
                    closest = sum;
                } else if (sum < target) {
                    left++;
                } else {
                    right--;
                }
            }
        }
        
        return closest;
    }
}

Followup:

Given an array of n integers nums and a target, find the number of index triplets i, j, k with 0 <= i < j < k < n that satisfy the condition nums[i] + nums[j] + nums[k] < target.

For example, given nums = [-2, 0, 1, 3], and target = 2.

Return 2. Because there are two triplets which sums are less than 2:

[-2, 0, 1]
[-2, 0, 3]

Follow up:
Could you solve it in O(n2) runtime?

Analysis:

very similar to 3Sum, only difference is to update the count that satisfies the condition. Note that the count will be updated to be right – left.

Time complexity: O(n^2)

Space complexity: O(1)

The code is below:

public class Solution {
    public int threeSumSmaller(int[] nums, int target) {
        // Two pointers O(n^2) O(1)
        
        if (nums == null || nums.length < 3) {
            return 0;
        }
        
        Arrays.sort(nums);
        
        int count = 0;
        
        for (int i = 0; i < nums.length - 2; i++) {
            // Below is two sum
            int left = i + 1;
            int right = nums.length - 1;
            
            while (left < right) {
                if (nums[i] + nums[left] + nums[right] < target) {
                    // There're right - left pairs satisfied the condition
                    count += right - left;
                    left++;
                } else {
                    right--;
                }
            }
        }
        
        return count;
    }
}

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 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 271 Encode and Decode Strings

Leetcode 271 Encode and Decode Strings

Design an algorithm to encode a list of strings to a string. The encoded string is then sent over the network and is decoded back to the original list of strings.

Machine 1 (sender) has the function:

string encode(vector<string> strs) {
  // ... your code
  return encoded_string;
}

Machine 2 (receiver) has the function:

vector<string> decode(string s) {
  //... your code
  return strs;
}

So Machine 1 does:

string encoded_string = encode(strs);

and Machine 2 does:

vector<string> strs2 = decode(encoded_string);

strs2 in Machine 2 should be the same as strs in Machine 1.

Implement the encode and decode methods.

Note:

  • The string may contain any possible characters out of 256 valid ascii characters. Your algorithm should be generalized enough to work on any possible characters.
  • Do not use class member/global/static variables to store states. Your encode and decode algorithms should be stateless.
  • Do not rely on any library method such as eval or serialize methods. You should implement your own encode/decode algorithm.

Analysis:

To encode the string, we can add some symbols before it. For example, for string “abc”, we can add the length 3 before it. However, for string starting from numbers, like 123abc. This could result in 6123abc, which is not acceptable. Then we add an ‘#’ between the length and the string.  So 3#abc is the decoded string.

To decode the string, we can search the ‘#’ symbol. The number before it is the length for the string, and the string after it with length is the string we want to decode.

public class Codec {

    // Encodes a list of strings to a single string.
    public String encode(List strs) {
        // encode with stringlength + "#" + str
        StringBuilder sb = new StringBuilder();
        for (String str : strs) {
            sb.append(str.length()).append("#").append(str);
        }
        return sb.toString();
    }

    // Decodes a single string to a list of strings.
    public List decode(String s) {
        List result = new LinkedList<>();
        
        // Corner case
        if (s == null || s.length() == 0) {
            return result;
        }
        
        int start = 0;
        int end = 0;
        
        while (end < s.length()) {
            if (s.charAt(end) == '#') {
                // find the length
                int length = Integer.valueOf(s.substring(start, end));
                // add the str
                result.add(s.substring(end + 1, end + 1 + length));
                // reset the start and the end
                start = end + 1 + length;
                end = start;
            }
            end++;
        }
       return result; 
    }
}