LeetCode Contest 52
这次比赛跪了。。
第一题Repeated String Match
二分查找。首先算出最少需要多少次才有可能使得B是子字符串:必须要保证重复后的A的长度不小于B的长度。我们可以简单算出最少需要重复:
最大次数j的上界是2i。然后对[i, j]这个区间进行二分查找。
这题竟然WA了2次(因为typo),TLE一次(一开始用j=10i)。。。
class Solution(object):
def repeatedStringMatch(self, A, B):
"""
:type A: str
:type B: str
:rtype: int
"""
i = (len(A) + len(B) - 1) / len(A)
j = 2 * i
ans = -1
while i <= j:
k = (i+j) / 2
tmp = A * k
if tmp.find(B) != -1:
ans = k
j = k - 1
else:
i = k + 1
return ans
空间上有很大的优化:我们可以自己写一个函数判断B是不是A重复k次后的子字符串。
第二题Longest Univalue Path
DFS。一开始重复计算导致TLE了。
# 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 longestUnivaluePath(self, root):
"""
:type root: TreeNode
:rtype: int
"""
ans = [0]
def dfs(root):
if not root:
return 0
l, r = dfs(root.left), dfs(root.right)
ml = 1
if l > 0 and root.left.val == root.val:
ml += l
mr = 1
if r > 0 and root.right.val == root.val:
mr += r
ans[0] = max(ans[0], ml+mr-2)
return max(ml, mr)
dfs(root)
return ans[0]
第三题Knight Probability in Chessboard
比赛的时候没有做出来。但是其实是简单的计数问题。按照乘法原理,k步之后仍然留在板上的概率是每步之后都留在板上的概率之积。
class Solution(object):
def knightProbability(self, N, K, r, c):
"""
:type N: int
:type K: int
:type r: int
:type c: int
:rtype: float
"""
b = [[[-1, 0] for _ in range(N)] for _ in range(N)]
b[r][c] = [0, 1]
ans = 1.0
for i in range(K):
ic = oc = 0
tb = [[[-1, 0] for _ in range(N)] for _ in range(N)]
for r in range(N):
for c in range(N):
if b[r][c][0] != i:
continue
for dr in (-1, -2, 1, 2):
for dc in (-1, -2, 1, 2):
if abs(dr) == abs(dc):
continue
nr, nc = r+dr, c+dc
if nr < 0 or nc < 0 or nr >= N or nc >= N:
oc += b[r][c][1]
continue
ic += b[r][c][1]
tb[nr][nc][0] = i+1
tb[nr][nc][1] += b[r][c][1]
if ic == 0:
return 0
ans *= (float(ic) / float(ic + oc))
b = tb
return ans
第四题Maximum Sum of 3 Non-Overlapping Subarrays
这是我这次比赛唯一一道直接AC的题目。不过代码写得不是很让我满意。我的想法是这样:进行三轮操作。第一轮操作算出以每个位置开始长度为k的子区间之和(第-个子区间的和)。第二轮操作对第一轮的结果进一步处理,算出以第i个区间为第二个子区间的最大和并记录区间的起始位置。第二轮操作结束后,我们得到了选择两个长度为k的区间的最优结果。第三轮操作跟第二轮操作类似,这次是找第三个子区间。三轮操作结束后再枚举一下所有可能的结果找出最大值就好。每轮的操作都是O(n)的。
每轮操作注意起始位置的选择范围。假设n是nums的长度。第一轮操作中,起始位置的选择范围是[0, n-k]。第二轮选择的时候,因为我们要保证选择的区间前面还有一个区间,所以起始位置的选择范围是[k, n-k]。类似地,第三轮起始位置的选择范围是[2k, n-k]。
最后说一下如何解决选择的区间不重复的问题(第二第三轮操作才有的问题)。以第二轮操作为例。我们保存对第i个区间(从位置i开始)可以选择的最优区间。在处理下一个区间(从位置i+1开始),那么让保存的最优区间与第i+1-k个区间(从位置i+1-k开始)比较,两者取最优者。这样我们得到的是对第i+1个区间可以选择的最优区间。这样我们就可以在保证不重复的同时能在O(n)完成每轮操作。
class Solution(object):
def maxSumOfThreeSubarrays(self, nums, k):
"""
:type nums: List[int]
:type k: int
:rtype: List[int]
"""
n = len(nums)
p = [0] * (n+1)
p[0] = nums[0]
for i in xrange(1, n):
p[i] = p[i-1] + nums[i]
# round 1
m = n-k+1
s = [0] * n
for i in range(m):
s[i] = p[i+k-1] - p[i-1]
# round 2
f = [None] * n
cm = ci = 0
for i in xrange(k, m):
if s[i-k] > cm:
cm, ci = s[i-k], i-k
f[i] = (s[i]+cm, ci, i)
# round 3
g = [None] * n
cm = ci = cj = 0
for i in xrange(2*k, m):
if f[i-k][0] > cm:
cm, ci, cj = f[i-k]
g[i] = (s[i]+cm, ci, cj, i)
# find answer
ans = None
cm = 0
for x in g:
if x is None or x[0] <= cm:
continue
cm = x[0]
ans = x[1:]
return ans