Leetcode 117: Populating Next Right Pointers in Each Node II

117. Populating Next Right Pointers in Each Node II 

  • Total Accepted: 74952
  • Total Submissions: 225622
  • Difficulty: Hard
  • Contributors: Admin

Follow up for problem “Populating Next Right Pointers in Each Node“.

What if the given tree could be any binary tree? Would your previous solution still work?

Note:

  • You may only use constant extra space.

For example,
Given the following binary tree,

         1
       /  \
      2    3
     / \    \
    4   5    7

After calling your function, the tree should look like:

         1 -> NULL
       /  \
      2 -> 3 -> NULL
     / \    \
    4-> 5 -> 7 -> NULL

 

Code 

from collections import deque
# Definition for binary tree with next pointer.
# class TreeLinkNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
#         self.next = None

class Solution:
    # @param root, a tree link node
    # @return nothing
    def connect(self, root):
        if root is None:
            return

        d = deque([(root, 0)])
        
        while d:
            if len(d) >= 2:
                # level is the same
                if d[0][1] == d[1][1]:
                    d[0][0].next = d[1][0]
                
            old_node, old_lvl = d.popleft()
            if old_node.left: d.append((old_node.left, old_lvl + 1))
            if old_node.right: d.append((old_node.right, old_lvl + 1))

 

Idea

Using BFS. Also look at the similar problem: https//nb4799.neu.edu/wordpress/?p=2044. Time complexity and space complexity are both O(N).

 

Code

# Definition for binary tree with next pointer.
# class TreeLinkNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
#         self.next = None

class Solution:
    
    def find_child(self, node, start_from_left_or_right):
        """ find the first occurrence of a child from the level of node.

        Return:
        1. child node
        2. its parent node
        3. "left" if it is the left child of its parent, otherwise "right"

        If child node is not found, return (None, None, None)
        """
        
        if node and start_from_left_or_right == 'right':
            if node.right:
                return node.right, node, 'right'
            else:
                node = node.next

        while node:
            if node.left:
                return node.left, node, 'left'
            elif node.right:
                return node.right, node, 'right'
            else:
                node = node.next

        return None, None, None


    # @param root, a tree link node
    # @return nothing
    def connect(self, root):
        if root is None: 
            return
        
        # pre is the first node in the previous layer
        pre = root
        
        while pre:
            # search the first child in the current layer
            first_child, first_child_parent, first_child_as_left_or_right = self.find_child(pre, 'left')
            pre = first_child

            while first_child is not None:
                # search the next child in the current layer
                if first_child_as_left_or_right == "left":
                    second_child, second_child_parent, second_child_as_left_or_right = \
                        self.find_child(first_child_parent, 'right')
                else:
                    second_child, second_child_parent, second_child_as_left_or_right = \
                        self.find_child(first_child_parent.next, 'left')
                
                if second_child is not None:
                    first_child.next = second_child
                    
                first_child, first_child_parent, first_child_as_left_or_right = \
                    second_child, second_child_parent, second_child_as_left_or_right                 



            
                

 

 

Idea

Modified from the O(1) space solution from: https//nb4799.neu.edu/wordpress/?p=2044

 

 

Leetcode 371: Sum of Two Integers

371. Sum of Two Integers 

  • Total Accepted: 42501
  • Total Submissions: 82322
  • Difficulty: Easy
  • Contributors: Admin

Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -.

Example:
Given a = 1 and b = 2, return 3.

 

Code

class Solution(object):
    def getSum(self, a, b):
        """
        :type a: int
        :type b: int
        :rtype: int
        """
        if a == 0:
            return b
        elif b == 0:
            return a
        
        mask = 0xffffffff

        # in Python, every integer is associated with its two's complement and its sign.
        # However, doing bit operation "& mask" loses the track of sign. 
        # Therefore, after the while loop, a is the two's complement of the final result as a 32-bit unsigned integer. 
        while b != 0:
            a, b = (a ^ b) & mask, ((a & b) << 1) & mask

        # a is negative if the first bit is 1
        if (a >> 31) & 1:
            return ~(a ^ mask)
        else:
            return a

 

Idea

Adding two integers a and b (no matter positive or negative) can always be boiled down into 3 steps:

  1. convert a and b into two’s complements.
  2. add both two’s complements. The result is a new two’s complement
  3. convert the result back to integer

 

Two things to note:
1. In Python, every integer is associated with its two’s complement and its sign. However, doing bit operation “& mask” loses the track of sign. For example, `-1 & 0xffffffff` becomes a huge positive number 4294967295. Therefore, after the while loop, a is the two’s complement of the final result as a **32-bit unsigned integer**.
2. The magic is that if there is a negative integer `n`, and its unsigned 32-bit two’s complement is `m`, then `m = ~(n ^ 0xffffffff)` and `n = ~(m ^ 0xffffffff)`. So using this magic, you can do the conversion in step 3.

 

Reference: https://discuss.leetcode.com/topic/65027/most-straightforward-python-solution

Leetcode 292: Nim Game

292. Nim Game

 
  • Total Accepted: 105850
  • Total Submissions: 194593
  • Difficulty: Easy
  • Contributors: Admin

You are playing the following Nim Game with your friend: There is a heap of stones on the table, each time one of you take turns to remove 1 to 3 stones. The one who removes the last stone will be the winner. You will take the first turn to remove the stones.

Both of you are very clever and have optimal strategies for the game. Write a function to determine whether you can win the game given the number of stones in the heap.

For example, if there are 4 stones in the heap, then you will never win the game: no matter 1, 2, or 3 stones you remove, the last stone will always be removed by your friend.

Hint:

  1. If there are 5 stones in the heap, could you figure out a way to remove the stones such that you will always be the winner?

 

Code

from collections import deque

class Solution(object):
    def canWinNim(self, n):
        """
        :type n: int
        :rtype: bool
        """
        if n <= 3:
            return True

        # when n = 1,2,3, you can always win
        d = deque([True] * 3)
        
        for i in xrange(4, n+1):
            newd = not (d[0] and d[1] and d[2])
            d.popleft()
            d.append(newd)

        return d[-1]

 

Idea

d contains three elements: when there are i-3, i-2 and i-1 remaining stones, can one have an optimal strategy to win? If they are all trues, no matter how many stones you take, your opponent will win.

 

Of course, this can be equivalent to: 

class Solution(object):
    def canWinNim(self, n):
        """
        :type n: int
        :rtype: bool
        """
        return n % 4 != 0

 

 

Leetcode 137: Single Number II

137. Single Number II

  • Total Accepted: 100365
  • Total Submissions: 253451
  • Difficulty: Medium
  • Contributors: Admin

Given an array of integers, every element appears three times except for one. Find that single one.

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

 
Code
class Solution(object):
    def singleNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        ans = 0

        for i in xrange(32):
            sum = 0
            for n in nums:
                # right shift in Python is unsigned
                # i.e., leftmost is filled with 0
                sum += (abs(n) >> i) & 1
            sum = sum % 3
            if sum != 0:
                ans = ans | (1 << i)
        
        negsign = 0
        for n in nums:
           if n < 0:
               negsign += 1
        negsign = negsign % 3
            
        if negsign != 0 :
            return -ans
        else:
            return ans

 

 
 
Idea
Although there is a convoluted algorithm using bit operation to solve this problem, I feel it is impossible to come up with that during an interview. 
 
suppose an integer is 32 bit. For each bit position, count how many numbers in nums are non-zero on that bit and store the count in sum.  When sum % 3 != 0, you know the exceptional number has 1 on that bit. (The prerequisite is that the exceptional number appears k times in nums where k % 3 != 0. This is the condition that the question does not specify right now but it did in the previous version.)
 
Integers in Python are not  implemented as fixed-size bits. The right shift in Python is unsigned (the leftmost position is filled with 0). Therefore, we need to count separately whether the exceptional number is negative or positive. (line 19-23)

Leetcode 72: Edit Distance

72. Edit Distance

  • Total Accepted: 71110
  • Total Submissions: 236049
  • Difficulty: Hard
  • Contributors: Admin

Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.)

You have the following 3 operations permitted on a word:

a) Insert a character
b) Delete a character
c) Replace a character

 

Code

class Solution(object):
    def minDistance(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        d = [[0]*(len(word2)+1) for i in xrange(len(word1)+1)]
        
        for i in xrange(len(word1)+1):
            d[i][0] = i

        for j in xrange(len(word2)+1):
            d[0][j] = j

        for i in xrange(1, len(word1)+1):
            for j in xrange(1, len(word2)+1):
                if word1[i-1] == word2[j-1]:
                    d[i][j] = d[i-1][j-1]
                else:
                    d[i][j] = min(d[i-1][j]+1,   # delete word1[i]
                                  d[i][j-1]+1,   # delete word2[j]
                                  d[i-1][j-1]+1  # replace word1[i] by word2[j]
                                  )
        return d[-1][-1] 

 

 

Idea

We maintain a 2D array d, where d[i][j] means the edit distance between the substring word1[:i] and word2[:j]

 

Code

class Solution(object):
    def minDistance(self, word1, word2):
        """
        :type word1: str
        :type word2: str
        :rtype: int
        """
        d = [i for i in xrange(len(word1)+1)]
      
        for j in xrange(1, len(word2)+1):
            pre = d[0]
            d[0] = j
            for i in xrange(1, len(word1)+1):      
                if word1[i-1] == word2[j-1]:
                    d[i], pre = pre, d[i]
                else:
                    d[i], pre = min(d[i-1]+1,  # delete word1[i]
                                    d[i]+1,    # delete word2[j]
                                    pre+1      # replace word1[i] by word2[j]
                                   ), d[i]
        return d[-1] 

 

Idea

Convert the 2D DP matrix into 1D. pre is the value of d[i-1][j-1] when d is 2D.

 

Reference

https://discuss.leetcode.com/topic/17639/20ms-detailed-explained-c-solutions-o-n-space

Leetcode 150: Evaluate Reverse Polish Notation

150. Evaluate Reverse Polish Notation

  • Total Accepted: 76968
  • Total Submissions: 304324
  • Difficulty: Medium
  • Contributors: Admin

Evaluate the value of an arithmetic expression in Reverse Polish Notation.

Valid operators are +, -, *, /. Each operand may be an integer or another expression.

Some examples:

  ["2", "1", "+", "3", "*"] -> ((2 + 1) * 3) -> 9
  ["4", "13", "5", "/", "+"] -> (4 + (13 / 5)) -> 6

 

Code

class Solution(object):
    def evalRPN(self, tokens):
        """
        :type tokens: List[str]
        :rtype: int
        """
        stk = []
        for s in tokens:
            try:
                # test whether s is a number
                int(s)
                stk.append(s)
            except:
                a = stk.pop()
                b = stk.pop()
                stk.append(str(int(eval(str(float(b)) + s + a))))
                
        return int(stk[-1])

 

Idea

Use stack. Every time you see an operator, pop the last element in the stack.

Leetcode 138: Copy List with Random Pointer

138. Copy List with Random Pointer

  • Total Accepted: 81110
  • Total Submissions: 308920
  • Difficulty: Hard
  • Contributors: Admin

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null.

Return a deep copy of the list.

 

Code

# Definition for singly-linked list with a random pointer.
# class RandomListNode(object):
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None

class Solution(object):
    def copyRandomList(self, head):
        """
        :type head: RandomListNode
        :rtype: RandomListNode
        """
        if head is None:
            return None
        
        # store copied nodes indexed by label
        copynodes = dict()
        copyhead = RandomListNode(head.label)
        head_bak = head
        copyhead_bak = copyhead
        
        # copy 'next' for each node
        while head.next:
            copyhead.next = RandomListNode(head.next.label)
            copynodes[head.next.label] = copyhead.next
            copyhead = copyhead.next
            head = head.next

        copyhead = copyhead_bak
        head = head_bak

        # copy 'random' for each node
        while head:
            if head.random:
                copyhead.random = copynodes[head.random.label]
            head = head.next
            copyhead = copyhead.next

        return copyhead_bak

 

Idea

Two rounds copy. In the first round, make sure node is copied and connected one by one. During the first round, also record newly copied nodes in a dictionary copynodes. In the second round, copy field random. You need to use the dictionary to locate the new copied nodes in constant time.

Note: This algorithm only works when no two nodes have the same label because we use node.label as keys in the dictionary.

 

More elegant way to utilize defaultdict:

# Definition for singly-linked list with a random pointer.
# class RandomListNode(object):
#     def __init__(self, x):
#         self.label = x
#         self.next = None
#         self.random = None

from collections import defaultdict
class Solution(object):
    def copyRandomList(self, head):
        """
        :type head: RandomListNode
        :rtype: RandomListNode
        """
        d = defaultdict(lambda: RandomListNode(0))
        d[None] = None
        tmp = head
        while tmp:
            d[tmp].label = tmp.label
            d[tmp].next = d[tmp.next]
            d[tmp].random = d[tmp.random]
            tmp = tmp.next
        return d[head]

 

Idea

d is a defaultdict. The key of d is original node and the value is the copied node.

 

Reference: https://discuss.leetcode.com/topic/5954/my-short-python-solution-with-o-n-complex-using-collections-defaultdict

 

Another very convoluted way to solve this problem. Only constant extra space will be used: https://discuss.leetcode.com/topic/7594/a-solution-with-constant-space-complexity-o-1-and-linear-time-complexity-o-n/2

Leetcode 136: Single Number

136. Single Number 

  • Total Accepted: 167202
  • Total Submissions: 320990
  • Difficulty: Easy
  • Contributors: Admin

Given an array of integers, every element appears twice except for one. Find that single one.

Note:
Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

 

Code

class Solution(object):
    def singleNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        res = 0
        for n in nums:
            res ^= n
        return res

 

Idea

A XOR B XOR A= B

Leetcode 76: Minimum Window Substring

76. Minimum Window Substring 

  • Total Accepted: 76479
  • Total Submissions: 332625
  • Difficulty: Hard
  • Contributors: Admin

Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).

For example,
S = "ADOBECODEBANC"
T = "ABC"

Minimum window is "BANC".

Note:
If there is no such window in S that covers all characters in T, return the empty string "".

If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.

 

Code

import sys
from collections import defaultdict

class Solution(object):
    def minWindow(self, s, t):
        """
        :type s: str
        :type t: str
        :rtype: str
        """
        mapping = defaultdict(int)
        for ch in t:
            mapping[ch] = mapping[ch] + 1
            
        d = sys.maxint
        valid = len(t)
        start = 0
        minstart, minend = None, None

        for end, ch in enumerate(s):
            if mapping[ch] > 0:
                valid -=1 
            mapping[ch] -= 1

            while valid == 0:
                if end - start + 1 < d:
                    minend, minstart = end, start
                    d = end - start + 1

                mapping[s[start]] += 1
                if mapping[s[start]] > 0:
                    valid += 1
                start += 1 
        
        if minstart is None:
            return ""
        else:
            return s[minstart:minend+1]
        
        

 

Idea

Create a dictionary mapping which stores how many times each character in t should appear. (line 11-13)

You have two pointers, start and end, which denote the border of the temporary window you are looking at. valid is a variable that when it reaches 0, we know the current window contains all characters in t. At first, `start` pointer is at index 0 and `end` pointer starts to move right.

When valid reaches 0,  you start to maintain the minimum string: you have variables d, minend and minstart and do the maintenance in line 26-28.

Then, you start to check whether a smaller window can also contains t. To do so, you move start pointer left. At the same time, you need to recover mapping dictionary.

 

Reference:

https://discuss.leetcode.com/topic/30941/here-is-a-10-line-template-that-can-solve-most-substring-problems

 

Leetcode 278: First Bad Version

278. First Bad Version

 Total Accepted: 68418
  • Total Submissions: 286586
  • Difficulty: Easy
  • Contributors: Admin

You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad.

Suppose you have n versions [1, 2, ..., n] and you want to find out the first bad one, which causes all the following ones to be bad.

You are given an API bool isBadVersion(version) which will return whether version is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API.

 

Code

# The isBadVersion API is already defined for you.
# @param version, an integer
# @return a bool
# def isBadVersion(version):

class Solution(object):
    def firstBadVersion(self, n):
        """
        :type n: int
        :rtype: int
        """
        left, right = 1, n
        while left < right:
            mid = left + (right - left) / 2
            if isBadVersion(mid):
                right = mid
            else:
                left = mid + 1
        
        return right

 

Idea

Binary Search.