题目序号

41. First Missing Positive

https://leetcode.com/problems/first-missing-positive/description/

# O(n) time
def firstMissingPositive(self, nums):
    for i in xrange(len(nums)):
        while 0 <= nums[i]-1 < len(nums) and nums[nums[i]-1] != nums[i]:
            tmp = nums[i]-1
            nums[i], nums[tmp] = nums[tmp], nums[i]
    for i in xrange(len(nums)):
        if nums[i] != i+1:
            return i+1
    return len(nums)+1

# O(nlgn) time
def firstMissingPositive(self, nums):
    nums.sort()
    res = 1
    for num in nums:
        if num == res:
            res += 1
    return res

296. Best Meeting Point

https://leetcode.com/problems/best-meeting-point/

def minTotalDistance(self, grid):
    if not grid:
        return 0
    r, c = len(grid), len(grid[0])
    sumr = [i for i in xrange(r) for j in xrange(c) if grid[i][j]]
    sumc = [j for i in xrange(r) for j in xrange(c) if grid[i][j]]
    sumr.sort()
    sumc.sort()
    mid_row = sumr[len(sumr)/2]
    mid_col = sumc[len(sumc)/2]
    return sum([abs(r-mid_row) for r in sumr]) + sum([abs(c-mid_col) for c in sumc])

87. Scramble String

https://leetcode.com/problems/scramble-string/

# DP
def isScramble1(self, s1, s2):
    if len(s1) != len(s2):
        return False
    if s1 == s2:
        return True
    if sorted(s1) != sorted(s2): # prunning
        return False
    for i in xrange(1, len(s1)):
        if (self.isScramble(s1[:i], s2[:i]) and self.isScramble(s1[i:], s2[i:])) or \
        (self.isScramble(s1[:i], s2[-i:]) and self.isScramble(s1[i:], s2[:-i])):
            return True
    return False

# DP with memorization
def __init__(self):
    self.dic = {}

def isScramble(self, s1, s2):
    if (s1, s2) in self.dic:
        return self.dic[(s1, s2)]
    if len(s1) != len(s2) or sorted(s1) != sorted(s2): # prunning
        self.dic[(s1, s2)] = False
        return False
    if s1 == s2:
        self.dic[(s1, s2)] = True
        return True
    for i in xrange(1, len(s1)):
        if (self.isScramble(s1[:i], s2[:i]) and self.isScramble(s1[i:], s2[i:])) or \
        (self.isScramble(s1[:i], s2[-i:]) and self.isScramble(s1[i:], s2[:-i])):
            return True
    self.dic[(s1, s2)] = False
    return False

99. Recover Binary Search Tree

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

# average O(lgn) space (worst case O(n) space), iteratively, one-pass
def recoverTree(self, root):
    res, stack, first, second = None, [], None, None
    while True:
        while root:
            stack.append(root)
            root = root.left
        if not stack:
            break
        node = stack.pop()
        # first time occurs reversed order
        if res and res.val > node.val:
            if not first:
                 first = res
            # first or second time occurs reversed order
            second = node
        res = node
        root = node.right
    first.val, second.val = second.val, first.val

# average O(lgn) space (worst case, O(n) space), recursively, one-pass
def recoverTree2(self, root):
    self.prevNode = TreeNode(-sys.maxsize-1)
    self.first, self.second = None, None
    self.inorder(root)
    self.first.val, self.second.val = self.second.val, self.first.val

def inorder(self, root):
    if not root:
        return
    self.inorder(root.left)
    if not self.first and self.prevNode.val > root.val:
        self.first, self.second = self.prevNode, root
    if self.first and self.prevNode.val > root.val:
        self.second = root
    self.prevNode = root
    self.inorder(root.right)

# average O(n+lgn) space, worst case O(2n) space, recursively, two-pass
def recoverTree3(self, root):
    res = []
    self.helper(root, res)
    first, second = None, None
    for i in xrange(1, len(res)):
        if not first and res[i-1].val > res[i].val:
            first, second = res[i-1], res[i]
        if first and res[i-1].val > res[i].val:
            second = res[i]
    first.val, second.val = second.val, first.val

def helper(self, root, res):
    if root:
        self.helper(root.left, res)
        res.append(root)
        self.helper(root.right, res)

97. Interleaving String

Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.

Example 1:

Input: s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbcbcac” Output: true Example 2:

Input: s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbbaccc” Output: false

# O(m*n) space
def isInterleave1(self, s1, s2, s3):
    r, c, l= len(s1), len(s2), len(s3)
    if r+c != l:
        return False
    dp = [[True for _ in xrange(c+1)] for _ in xrange(r+1)]
    for i in xrange(1, r+1):
        dp[i][0] = dp[i-1][0] and s1[i-1] == s3[i-1]
    for j in xrange(1, c+1):
        dp[0][j] = dp[0][j-1] and s2[j-1] == s3[j-1]
    for i in xrange(1, r+1):
        for j in xrange(1, c+1):
            dp[i][j] = (dp[i-1][j] and s1[i-1] == s3[i-1+j]) or \
               (dp[i][j-1] and s2[j-1] == s3[i-1+j])
    return dp[-1][-1]

# O(2*n) space
def isInterleave2(self, s1, s2, s3):
    l1, l2, l3 = len(s1)+1, len(s2)+1, len(s3)+1
    if l1+l2 != l3+1:
        return False
    pre = [True for _ in xrange(l2)]
    for j in xrange(1, l2):
        pre[j] = pre[j-1] and s2[j-1] == s3[j-1]
    for i in xrange(1, l1):
        cur = [pre[0] and s1[i-1] == s3[i-1]] * l2
        for j in xrange(1, l2):
            cur[j] = (cur[j-1] and s2[j-1] == s3[i+j-1]) or \
                     (pre[j] and s1[i-1] == s3[i+j-1])
        pre = cur[:]
    return pre[-1]

# O(n) space
def isInterleave3(self, s1, s2, s3):
    r, c, l= len(s1), len(s2), len(s3)
    if r+c != l:
        return False
    dp = [True for _ in xrange(c+1)]
    for j in xrange(1, c+1):
        dp[j] = dp[j-1] and s2[j-1] == s3[j-1]
    for i in xrange(1, r+1):
        dp[0] = (dp[0] and s1[i-1] == s3[i-1])
        for j in xrange(1, c+1):
            dp[j] = (dp[j] and s1[i-1] == s3[i-1+j]) or (dp[j-1] and s2[j-1] == s3[i-1+j])
    return dp[-1]

# DFS
def isInterleave4(self, s1, s2, s3):
    r, c, l= len(s1), len(s2), len(s3)
    if r+c != l:
        return False
    stack, visited = [(0, 0)], set((0, 0))
    while stack:
        x, y = stack.pop()
        if x+y == l:
            return True
        if x+1 <= r and s1[x] == s3[x+y] and (x+1, y) not in visited:
            stack.append((x+1, y)); visited.add((x+1, y))
        if y+1 <= c and s2[y] == s3[x+y] and (x, y+1) not in visited:
            stack.append((x, y+1)); visited.add((x, y+1))
    return False

# BFS
def isInterleave(self, s1, s2, s3):
    r, c, l= len(s1), len(s2), len(s3)
    if r+c != l:
        return False
    queue, visited = [(0, 0)], set((0, 0))
    while queue:
        x, y = queue.pop(0)
        if x+y == l:
            return True
        if x+1 <= r and s1[x] == s3[x+y] and (x+1, y) not in visited:
            queue.append((x+1, y)); visited.add((x+1, y))
        if y+1 <= c and s2[y] == s3[x+y] and (x, y+1) not in visited:
            queue.append((x, y+1)); visited.add((x, y+1))
    return False

174. Dungeon Game

The demons had captured the princess (P) and imprisoned her in the bottom-right corner of a dungeon. The dungeon consists of M x N rooms laid out in a 2D grid. Our valiant knight (K) was initially positioned in the top-left room and must fight his way through the dungeon to rescue the princess.

The knight has an initial health point represented by a positive integer. If at any point his health point drops to 0 or below, he dies immediately.

Some of the rooms are guarded by demons, so the knight loses health (negative integers) upon entering these rooms; other rooms are either empty (0’s) or contain magic orbs that increase the knight’s health (positive integers).

In order to reach the princess as quickly as possible, the knight decides to move only rightward or downward in each step.

Write a function to determine the knight’s minimum initial health so that he is able to rescue the princess.

For example, given the dungeon below, the initial health of the knight must be at least 7 if he follows the optimal path RIGHT-> RIGHT -> DOWN -> DOWN.

Note:

The knight’s health has no upper bound. Any room can contain threats or power-ups, even the first room the knight enters and the bottom-right room where the princess is imprisoned.

# O(m*n) space
def calculateMinimumHP1(self, dungeon):
    if not dungeon:
        return
    r, c = len(dungeon), len(dungeon[0])
    dp = [[0 for _ in xrange(c)] for _ in xrange(r)]
    dp[-1][-1] = max(1, 1-dungeon[-1][-1])
    for i in xrange(c-2, -1, -1):
        dp[-1][i] = max(1, dp[-1][i+1]-dungeon[-1][i])
    for i in xrange(r-2, -1, -1):
        dp[i][-1] = max(1, dp[i+1][-1]-dungeon[i][-1])
    for i in xrange(r-2, -1, -1):
        for j in xrange(c-2, -1, -1):
            dp[i][j] = max(1, min(dp[i+1][j], dp[i][j+1])-dungeon[i][j])
    return dp[0][0]

# O(n) space
def calculateMinimumHP(self, dungeon):
    if not dungeon:
        return
    r, c = len(dungeon), len(dungeon[0])
    dp = [0 for _ in xrange(c)]
    dp[-1] = max(1, 1-dungeon[-1][-1])
    for i in xrange(c-2, -1, -1):
        dp[i] = max(1, dp[i+1]-dungeon[-1][i])
    for i in xrange(r-2, -1, -1):
        dp[-1] = max(1, dp[-1]-dungeon[i][-1])
        for j in xrange(c-2, -1, -1):
            dp[j] = max(1, min(dp[j], dp[j+1])-dungeon[i][j])
    return dp[0]

>>> from timeit import timeit
>>> c = 100
>>> timeit(lambda: [0 for _ in xrange(c)])
10.002701801200814
>>> timeit(lambda: [0] * c)
1.77059385744343

115. Distinct Subsequences

Given a string S and a string T, count the number of distinct subsequences of S which equals T.

A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, “ACE” is a subsequence of “ABCDE” while “AEC” is not).

Example 1:

Input: S = “rabbbit”, T = “rabbit” Output: 3 Explanation:

As shown below, there are 3 ways you can generate “rabbit” from S. (The caret symbol ^ means the chosen letters)

rabbbit ^^^^ ^^ rabbbit ^^ ^^^^ rabbbit ^^^ ^^^ Example 2:

Input: S = “babgbag”, T = “bag” Output: 5 Explanation:

As shown below, there are 5 ways you can generate “bag” from S. (The caret symbol ^ means the chosen letters)

babgbag ^^ ^ babgbag ^^ ^ babgbag ^ ^^ babgbag

^ ^^
babgbag
^^^
# O(m*n) space
def numDistinct1(self, s, t):
    l1, l2 = len(s)+1, len(t)+1
    dp = [[1] * l2 for _ in xrange(l1)]
    for j in xrange(1, l2):
        dp[0][j] = 0
    for i in xrange(1, l1):
        for j in xrange(1, l2):
            dp[i][j] = dp[i-1][j] + dp[i-1][j-1]*(s[i-1] == t[j-1])
    return dp[-1][-1]

# O(n) space
def numDistinct(self, s, t):
    l1, l2 = len(s)+1, len(t)+1
    cur = [0] * l2
    cur[0] = 1
    for i in xrange(1, l1):
        pre = cur[:]
        for j in xrange(1, l2):
            cur[j] = pre[j] + pre[j-1]*(s[i-1] == t[j-1])
    return cur[-1]

233. Number of Digit One

Given an integer n, count the total number of digit 1 appearing in all non-negative integers less than or equal to n.

Example:

Input: 13 Output: 6 Explanation: Digit 1 occurred in the following numbers: 1, 10, 11, 12, 13.

def countDigitOne(self, n):
    if n <= 0:
        return 0
    if 1 <= n <= 9:
        return 1
    # compute the first bit
    head, level = n, 1
    while head > 9:
        level *= 10
        head //= 10
    # if the first bit is 1
    # like 191, divide it into (0-99), (0-91) and the first bit in (100, 101, 1.., 191)
    if head == 1:
        return  self.countDigitOne(level-1) + self.countDigitOne(n-level) + n-level +1
    # like 491, divide it into (0-99), (100-199), (200-299, 300-399) and (400-491)
    return (head) * self.countDigitOne(level-1) + self.countDigitOne(n-head*level) + level