Leetcode 99: Validate Binary Search Tree

https://leetcode.com/problems/validate-binary-search-tree/

Validate Binary Search Tree

Total Accepted: 65929 Total Submissions: 326515 Difficulty: Medium

Given a binary tree, determine if it is a valid binary search tree (BST).

Assume a BST is defined as follows:

  • The left subtree of a node contains only nodes with keys less than the node’s key.
  • The right subtree of a node contains only nodes with keys greater than the node’s key.
  • Both the left and right subtrees must also be binary search trees.

confused what "{1,#,2,3}" means? > read more on how binary tree is serialized on OJ.

OJ’s Binary Tree Serialization:

The serialization of a binary tree follows a level order traversal, where ‘#’ signifies a path terminator where no node exists below.

Here’s an example:

   1
  / \
 2   3
    /
   4
    \
     5

The above binary tree is serialized as "{1,2,3,#,#,4,#,#,5}".

 

Code

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def isValidBST(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
        return self.helper(root, None, None)
        
    def helper(self, root, min, max):
            if not root:
                return True

            if (min is not None and root.val <= min) or (max is not None and root.val >= max):
                return False
            
            return self.helper(root.left, min, root.val) and self.helper(root.right, root.val, max)

 

Idea

Just check the basic rule of BST: all nodes in a node’s left subtree should be less than the node’s value. all nodes in a node’s right subtree should be larger than the node’s value. 

 

Another Code

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def isValidBST(self, root):
        """
        :type root: TreeNode
        :rtype: bool
        """
        self.prev = None
        return self.inorder(root)

    def inorder(self, root):
        if not root:
            return True
        if not self.inorder(root.left):
            return False
        if self.prev and self.prev.val >= root.val:
            return False
        self.prev = root
        return self.inorder(root.right)
                

Idea

We use another property of BST: the inorder traversal of BST should return us an ascending order of numbers. We can do inorder traversal with a variable (`prev` in our code) recording which node we visited before we are visiting the current node. Whenever we find `prev.val` is larger than the current node’s value, we report invalidity of the tree.

leetcode 61: Rotate List

https://leetcode.com/problems/rotate-list/

Rotate List

Total Accepted: 50875 Total Submissions: 233034 Difficulty: Medium

Given a list, rotate the list to the right by k places, where k is non-negative.

For example:
Given 1->2->3->4->5->NULL and k = 2,
return 4->5->1->2->3->NULL.

 

Code

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def rotateRight(self, head, k):
        """
        :type head: ListNode
        :type k: int
        :rtype: ListNode
        """
        if not head:
            return None
            
        len_cnt = 0
        tail_reach = False
        fast = head
        while k:
            len_cnt += 1
            if not fast.next:
                tail_reach = True
                fast = head
            else:
                fast = fast.next
            k -= 1
            if tail_reach:
                k %= len_cnt
        
        if fast == head:
            return head
        
        slow = head
        while fast.next:
            fast = fast.next
            slow = slow.next
        
        fast.next = head
        new_head = slow.next
        slow.next = None
        return new_head
                
           
        
        

 

Idea

Use `fast` pointer to traverse `k` nodes. Then use a slow pointer to traverse from head. Both fast and slow pointers traverse one node by one node, until fast pointer reaches the end  (line 35-37). Therefore, the slow pointer traverses exactly len(nums)-k nodes. Its next node should be the new head.

 

More succinct code can be found: https://discuss.leetcode.com/topic/14470/my-clean-c-code-quite-standard-find-tail-and-reconnect-the-list

Leetcode 26: Remove Duplicates from Sorted Array

https://leetcode.com/problems/remove-duplicates-from-sorted-array/

Remove Duplicates from Sorted Array

Total Accepted: 87967 Total Submissions: 280545 Difficulty: Easy

Given a sorted array, remove the duplicates in place such that each element appear only once and return the new length.

Do not allocate extra space for another array, you must do this in place with constant memory.

For example,
Given input array nums = [1,1,2],

Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively. It doesn’t matter what you leave beyond the new length.

 

Code

class Solution(object):
    def removeDuplicates(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0
        if len(nums)==1:
            return 1
            
        prev = nums[0]
        del_cnt = 0
        for i in xrange(1, len(nums)):
            idx = i- del_cnt
            if nums[idx] == prev:
                nums.pop(idx)
                del_cnt += 1
            else:
                prev = nums[idx]
            
        return len(nums)
        

 

Idea

My code doesn’t only return the length of non-duplicated elements but also pop duplicated elements in the original array.

 

Code that does not need to pop: https://discuss.leetcode.com/topic/3102/my-solution-time-o-n-space-o-1

Leetcode 53: Maximum Subarray

https://leetcode.com/problems/maximum-subarray/

Maximum Subarray

Total Accepted: 79595 Total Submissions: 227725 Difficulty: Medium

Find the contiguous subarray within an array (containing at least one number) which has the largest sum.

For example, given the array [−2,1,−3,4,−1,2,1,−5,4],
the contiguous subarray [4,−1,2,1] has the largest sum = 6.

click to show more practice.

More practice:

If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

 

Code

import sys
class Solution(object):
    def maxSubArray(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
            
        max_sum = -sys.maxint
        tmp_sum = 0
        
        for i in xrange(0, len(nums)):
            if tmp_sum + nums[i] >= 0:
                tmp_sum += nums[i]
                max_sum = max(max_sum, tmp_sum)
            else:
                tmp_sum = 0
                # for corner case where the array only contains negative nums
                max_sum = max(max_sum, nums[i])
                
        return max_sum

 

Idea

We create a variable `tmp_sum` to record what is the maximum sum you have seen. If you visit a positive number, you can definitely add it to `tmp_sum`; if you visit a negative number, as long as `tmp_sum` is still larger than 0, you can add it also. If a negative number makes `tmp_sum` to negative, that means the maximum sum cannot happen by including this negative number and any arbitrary numbers before it.

 

Another idea is to use divide and conquer:

https://leetcode.com/discuss/694/how-solve-maximum-subarray-using-divide-and-conquer-approach

Step1. Select the middle element of the array. So the maximum subarray may contain that middle element or not.

Step 2.1 If the maximum subarray does not contain the middle element, then we can apply the same algorithm to the the subarray to the left of the middle element and the subarray to the right of the middle element.

Step 2.2 If the maximum subarray does contain the middle element, then the result will be simply the maximum suffix subarray of the left subarray plus the maximum prefix subarray of the right subarray

Step 3 return the maximum of those three answer.

Here is a sample code for divide and conquer solution. Please try to understand the algorithm before look at the code:

class Solution {
public:
    int maxSubArray(int A[], int n) {
        // IMPORTANT: Please reset any member data you declared, as
        // the same Solution instance will be reused for each test case.
        if(n==0) return 0;
        return maxSubArrayHelperFunction(A,0,n-1);
    }
    
    int maxSubArrayHelperFunction(int A[], int left, int right) {
        if(right == left) return A[left];
        int middle = (left+right)/2;
        int leftans = maxSubArrayHelperFunction(A, left, middle);
        int rightans = maxSubArrayHelperFunction(A, middle+1, right);
        int leftmax = A[middle];
        int rightmax = A[middle+1];
        int temp = 0;
        for(int i=middle;i>=left;i--) {
            temp += A[i];
            if(temp > leftmax) leftmax = temp;
        }
        temp = 0;
        for(int i=middle+1;i<=right;i++) {
            temp += A[i];
            if(temp > rightmax) rightmax = temp;
        }
        return max(max(leftans, rightans),leftmax+rightmax);
    }
};

 

The divide and conquer algorithm takes O(nlogn) time and O(n) space just as merge sort.

Leetcode 60: Permutation Sequence

Total Accepted: 40547 Total Submissions: 173795 Difficulty: Medium

The set [1,2,3,…,<i>n</i>] contains a total of n! unique permutations.

By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = 3):

  1. "123"
  2. "132"
  3. "213"
  4. "231"
  5. "312"
  6. "321"

Given n and k, return the kth permutation sequence.

Note: Given n will be between 1 and 9 inclusive.

 

Code

class Solution(object):
    def getPermutation(self, n, k):
        """
        :type n: int
        :type k: int
        :rtype: str
        """
        res = ""
        arr = range(1, n+1)
        k = k-1
        for i in xrange(n-1, -1, -1):
            idx, k = divmod(k, math.factorial(i))
            res += str(arr.pop(idx))
        return res

 

Idea

Always try to determine which is the next character to append.

For example,

n=3, we have 6 permutations in total:

123
132
213
231
312
321

If k=3, we know we should return 213. We should first determine we need to append “2”. How to determine that? we know that there are (n-1)! permutations that start with “1”, “2” and “3” each. So the integer quotient of (k-1)/(n-1)! represents the index (0-based) of the number in the original array (1,2,3).  

You keep doing this iteratively to get the final result.

Leetcode 46: Permutations

https://leetcode.com/problems/permutations/

Permutations

Total Accepted: 70053 Total Submissions: 214523 Difficulty: Medium

Given a collection of numbers, return all possible permutations.

For example,
[1,2,3] have the following permutations:
[1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], and [3,2,1].

 

Code

class Solution(object):
    def permute(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        if not nums:
            return []
        res = []
        self.recur(nums, 0, res)
        return res
        
    def recur(self, nums, pos, res):
        if pos == len(nums):
            res.append(nums[:])
            
        for i in xrange(pos, len(nums)):
            nums[i], nums[pos] = nums[pos], nums[i]
            self.recur(nums, pos+1, res)
            nums[i], nums[pos] = nums[pos], nums[i]

 

Idea

We can observe the following process to obtain permutations:

1’s permutation = 1

{1,2}’s permutation = {1,2} and {2,1}. Essentially, it is 1+{2}’s permutation and 2+{1}’s permutation

{1,2,3}’s permutation = 1+{2,3}’s permutation, 2+{1,3}’s permutation, 3+{2,1}’s permutation.

Therefore we can obtain all the permutations by:

  1. swap the first element with any element after it.
  2. get the permutation of nums[1:]

We can recursively do this to get the result.

Leetcode 99: Recover Binary Search Tree

https://leetcode.com/problems/recover-binary-search-tree/

Recover Binary Search Tree

Total Accepted: 41308 Total Submissions: 166942 Difficulty: Hard

Two elements of a binary search tree (BST) are swapped by mistake.

Recover the tree without changing its structure.

Note:
A solution using O(n) space is pretty straight forward. Could you devise a constant space solution?

confused what "{1,#,2,3}" means? > read more on how binary tree is serialized on OJ.

OJ’s Binary Tree Serialization:

The serialization of a binary tree follows a level order traversal, where ‘#’ signifies a path terminator where no node exists below.

Here’s an example:

   1
  / \
 2   3
    /
   4
    \
     5

The above binary tree is serialized as "{1,2,3,#,#,4,#,#,5}".

 
 
 

Code

import sys
# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def __init__(self):
        self.prev = TreeNode(-sys.maxint)
        
    def recoverTree(self, root):
        """
        :type root: TreeNode
        :rtype: void Do not return anything, modify root in-place instead.
        """
        brk_nodes = []
        self.inorder(root, brk_nodes)
            
        brk_nodes[0].val, brk_nodes[1].val = brk_nodes[1].val, brk_nodes[0].val
        
        
    def inorder(self, root, brk_nodes):
        def add_to_brk(prev):
            if len(brk_nodes)==0:
                brk_nodes.append(prev)
                brk_nodes.append(root)
            else:
                brk_nodes[1] = root
                    
        # traverse left            
        if root.left:
            self.inorder(root.left, brk_nodes)
            
        if self.prev.val > root.val:
            add_to_brk(self.prev)
        
        self.prev = root
        
        # traverse right
        if root.right:
            self.inorder(root.right, brk_nodes)

        

 

Idea

We use the property that if a BST is valid, its inorder traversal will return the data in ascending order. For example, the top tree in the following plot is a valid binary search tree. Therefore, its inorder traversal should return 13489. All elements are larger than their previous elements.

tt (3)

The three trees on the bottom are all invalid binary search trees, each with exactly two nodes exchanged (marked as red). You may recognize that an inorder traversal of an invalid BST has at most two places where an element is smaller than the element right before it. More specifically:

The bottom left tree: inorder traversal is 93481. 3 is smaller than 9. 1 is smaller than 8.

The bottom middle tree: inorder traversal is 13498. 8 is smaller than 9.

The bottom right tree: inorder traversal is 18439. 4 is smaller than 8. 3 is smaller than 4.

Using this rule, we implement our code whenever we find previous visited node has larger value than the current node’s value. Whenever we find such node and the current broken node list is empty, we add the previous element and the current element together, although the current element may or may not be the broken node. (Line 27-28) But writing in this way will help us deal with the cases when the inorder traversal only contains one misplacement of number (e.g., the bottom middle tree in the plot).

Since we at most call O(N) recursive calls of `self.inorder()` function, the space complexity is O(N). The time complexity is O(N) because in the worst case you need to traverse all elements before you determine the two broken nodes.

 

Reference

The same idea applied in this post: https://leetcode.com/discuss/13034/no-fancy-algorithm-just-simple-and-powerful-order-traversal
This problem which is more space efficient: https://leetcode.com/discuss/26310/detail-explain-about-morris-traversal-finds-incorrect-pointer

Leetcode 239: Sliding Window Maximum

https://leetcode.com/problems/sliding-window-maximum/

Sliding Window Maximum

Total Accepted: 13329 Total Submissions: 57131 Difficulty: Hard

Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position.

For example,
Given nums = [1,3,-1,-3,5,3,6,7], and k = 3.

Window position                Max
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

Therefore, return the max sliding window as [3,3,5,5,6,7].

Note:
You may assume k is always valid, ie: 1 ≤ k ≤ input array’s size for non-empty array.

Follow up:
Could you solve it in linear time?

 

Code

from collections import *
class Solution(object):
    def maxSlidingWindow(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: List[int]
        """
        res = []
        # deque of (idx, val)
        q = deque()
        for i,v in enumerate(nums):
            while q and q[0][0] < i-(k-1):
                q.popleft()
            while q and q[-1][1] < v:
                q.pop()
            q.append((i, v))
            if i >= k-1:
                res.append(q[0][1])
        return res

 

Idea

An O(N) time complexity algorithm. Each element is appended to and popped out of the deque at most one time. Idea can be found here: https://leetcode.com/discuss/46578/java-o-n-solution-using-deque-with-explanation

Find Kth Smallest Element in Two Sorted Arrays

Problem

Given K and two sorted arrays with length M and N, find the K-th smallest element among all elements in the two arrays.

 

Code

import sys
class Solution(object):
    def findKthSmallest(self, nums1, nums2, k):
        """
        :type nums1: sorted List[int]
        :type nusm2: sorted List[int]
        :type k: int
        :rtype: int
        """
        if not (0 <k <= len(nums1)+len(nums2)):
            return None

        while True:
            i = int(float(len(nums1))/(len(nums1)+len(nums2))*(k-1))
            j = k-1-i
            nums1_i = nums1[i] if i < len(nums1) else sys.maxint 
            nums1_i_1 =  nums1[i-1] if i-1>=0 else -sys.maxint      
            nums2_j = nums2[j] if j < len(nums2) else sys.maxint
            nums2_j_1 = nums2[j-1] if j-1>=0 else -sys.maxint

            if nums2_j_1 <= nums1_i <= nums2_j:
                return nums1_i
            if nums1_i_1 <=nums2_j<=nums1_i:
                return nums2_j
        
            if nums1_i < nums2_j:
                k = k - i - 1
                nums1 = nums1[i+1:]
                nums2 = nums2[:j]
            else:
                k = k - j - 1
                nums1 = nums1[:i]
                nums2 = nums2[j+1:]
                

s = Solution()
print s.findKthSmallest([2,3,4,5], [], 3)
print s.findKthSmallest([], [2,3,4,5], 3)
print s.findKthSmallest([2,3,4,5,5], [6,7,8], 6)

 

Idea

A very straightforward method requires O(K) time: You can use two pointers pointing from the heads of the two lists. Every time you compare which pointer points to a smaller number and push the smaller number to your result list. After that, you make the pointer point to the next element. 

Our method can achieve O(log(M+N)) time: the idea can be found here. It is similar to the idea to find median in two sorted arrays. The difference is that at line 14 we don’t simply assign `i` with `(len(nums1)+len(nums2))/2`. We must make sure i will be assigned valid value (between 0 and len(nums1)) every time. So we assign `i` as proportionally to nums1’s length: i = int(float(len(nums1))/(len(nums1)+len(nums2))*(k-1)) 

Leetcode 43: Multiply Strings

https://leetcode.com/problems/multiply-strings/

Multiply Strings

Total Accepted: 43669 Total Submissions: 203735 Difficulty: Medium

Given two numbers represented as strings, return multiplication of the numbers as a string.

Note: The numbers can be arbitrarily large and are non-negative.

It is not a very funny problem that can test you in the interview.

 

Refer Idea here:

https://leetcode.com/discuss/33951/ac-solution-in-java-with-explanation

Refer Python Code here:

https://leetcode.com/discuss/50707/simple-python-solution-18-lines

 

Updated 2016-10-31:

Actually this problem can be solved elegantly. 

 

Code

class Solution(object):
    def multiply(self, num1, num2):
        """
        :type num1: str
        :type num2: str
        :rtype: str
        """
        m, n = len(num1), len(num2)
        pos = [0] * (m+n)

        for i in xrange(m-1, -1, -1):
            for j in xrange(n-1, -1, -1):
                d1, d2 = int(num1[i]), int(num2[j])
                sum = d1 * d2 + pos[i+j+1] 
                pos[i+j] += sum/10
                pos[i+j+1] = sum % 10

        res = ''
        for p in pos:
            if not (not res and not p):
                res += str(p)

        return res if res else '0'

 

Idea

Screen Shot 2016-11-08 at 10.40.37 AM

Don’t worry about pos[i+j] += sum/10 (line 15) will become greater than 10. It will ultimately be taken mod when smaller i or j is traversed.

 

Reference: https://discuss.leetcode.com/topic/30508/easiest-java-solution-with-graph-explanation/2