每日一题-Trap_Water

[每日一题] (Trapping Rain Water II)
Trapping Rain Water II
Given n x m non-negative integers representing an elevation map 2d where the area of each cell is 1 x 1, compute how much water it is able to trap after raining.

Example
Given 5*4 matrix

[12,13,0,12]
[13,4,13,12]
[13,8,10,12]
[12,13,12,12]
[13,13,13,13]
return 14.

解题思路


使用最小堆
1.对矩形的四周建堆
2.对于堆中每一元素,查探其四邻域中未查探的位置
3.如果h小于当前值,则更新水池容量,并将该位置加入堆中
4.如果h大于等于当前值,则直接加入堆中
最小堆中每次取的元素为当前水池中最短边的长度,如果每次寻找时发现了比最短边低的位置,则可以将水导入(更新水池容量),否则直接将该位置加入到水池中形成新的边缘

笔记

  最小堆的题目的特征(不断找最小),对Python中的最小堆的使用

Python:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#!/usr/bin/env
# -*- coding:utf-8 -*-
import heapq
M = [[12, 13, 0, 12], [13, 4, 13, 12], [13, 8, 10, 12], [12, 13, 12, 12], [13, 13, 13, 13]]
class Solution(object):
def trapWater(self, M):
heap = []
heapq.heapify(heap)
d = [(0, 1), (0, -1), (1, 0), (-1, 0)]
n = len(M)
m = len(M[0])
visit = [[0 for i in xrange(m)] for I in xrange(n)]
res = 0
for i in xrange(n):
for I in xrange(m):
if i == 0 or I == 0 or i == n-1 or I == m-1:
heapq.heappush(heap, (M[i][I], i, I))
visit[i][I] = 1
while heap != []:
this = heapq.heappop(heap)
for i in xrange(4):
h = this[0]
nr = this[1] + d[i][0]
nl = this[2] + d[i][1]
if nr < 0 or nl < 0 or nr >= n or nl >= m:
continue
if visit[nr][nl] == 1:
continue
visit[nr][nl] = 1
tmp = M[nr][nl]
if tmp < h:
res += h - tmp
tmp = h
heapq.heappush(heap, (tmp, nr, nl))
return res


每日一题-二叉树最长连续路径

[每日一题] (二叉树最长连续路径)
在一个二叉树中找出最长连续递增的path,输出path中node的个数。path只能从上到下
Follow-up:path可以从下到上然后从上到下

解题思路


本次的代码没有经过具体测试,仅作讨论用途-.-
原题: 使用递归,每次都计算当前最长路径长度
Follow-up: 使用递归,每次递归的时候计算以当前结点为子树时的最长路径以及与父结点的连续路径。
     具体方法是在每个结点递归调用两次函数,计算左右子树的最长路径长度和连续路径长度,然后比较后返回以该结点为子树最长路径长度和连续路径长度

Python:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#!/usr/bin/env
# -*- coding:utf-8 -*-
# 原题
class Solution(object):
def longestPath(self, root):
if root == None:
return 0
left = self.recursive(root.left, root.val, 1) # 求左边子树的最大长度
right = self.recursive(root.right, root.val, 1) # 求右边子树的最大长度
return max(left, 1, right)
def recursive(self, node, preVal, tempLength):
if node == None:
return 0
thisLength = tempLength + 1 if node.val == preVal + 1 else 1 # 如果该节点和父节点连续,则当前最大长度为父节点的最大长度+1,否则为1
left = self.recursive(node.left, node.val, thisLength) # 找左子树最大长度
right = self.recursive(node.right, node.val, thisLength) # 找右子树最大长度
return max(left, thisLength, right) # 返回当前节点以后的节点的最大路径长度
# Follow-up
class Solution(object):
def longestPath(self, root):
if root == None:
return 0
left, Lbig, Lsmall= self.recursive(root.left, root.val) # left代表左子树的最长路径长度, Lbig代表root节点左子树中比root大的连续路径长度, Lsmall代表root节点左子树中比root小的连续路径长度
right, Rbig, Rsmall = self.recursive(root.right, root.val) # right代表右子树的最长路径长度, Rbig代表root节点右子树中比root大的连续路径长度, Rsmall代表root节点右子树中比root小的连续路径长度
thisLength = max(left, right, Lbig+1+Rsmall, Rbig+1+Lsmall) # 以当前节点为根的子树的最长路径长度
return thisLength
def recursive(self, node, preVal): # 每次递归计算出以当前node为根的子树的最长路径长度
if root == None:
return 0, 0, 0
left, Lbig, Lsmall = self.recursive(root.left, root.val)
right, Rbig, Rsmall = self.recursive(root.right, root.val)
thisLength = max(left, right, Lbig+1+Rsmall, Rbig+1+Lsmall)
if root.val == preVal + 1:
return thisLength, max(Lbig, Rbig)+1, 0
elif root.val == preVal - 1:
return thisLength, 0, max(Lsmall, Rsmall)+1
else:
return thisLength, 0, 0

每日一题-石之游戏

[每日一题] (石之游戏)
n堆石头排成一行,你每次可以把相邻的2堆石头聚成1堆,聚合后的石头数会成为你的分数的一部分。
问当进行n-1次,所有石头聚成一堆后,怎么使得总分最小。

例子: [3, 4, 3]
  第一次 3+4=7 -> [7, 3]
  第二次 (7) + 7 + 3 = 17 -> [17]
  总分17最少。

Follow-up(Google onsite): 变成一个环

解题思路


使用动态规划,思路可参考算法导论的矩阵链乘法。
状态转移矩阵:
  p[i][j] = min[p[i][k] + p[k+1][j] + s[i][j]] (i<=k<=j)
  s[i][j] = s[i][k] + s[k+1][j]
其中p[i][j]表示从i合并到j所得的最小分数,s[i][j]表示从i合并到j所得出的数

Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/env
# -*- coding:utf-8 -*-
"""
时间复杂度 O(n^3)
"""
stone = [16,11,7,17,11,7,9,2,17,20,22,7,5,17,6,14,21,2,9,2,15,20,14,6,12,16,9,8,14,5,1,12,4,19,5,14,22,20,13,12,19,14,3,6,17,21,13,17,8,9,18,1,8,12,5,20,2,7,14,22,14,7,12,20,22,2,13,15,9,14,20,13,3,18,8,10,20,10,18,21]
N = len(stone)
class Solution(object):
def stoneGame(self, stone, N):
p = [[0 for i in xrange(N)] for j in xrange(N)] # p[i][j]代表合并i到j的最优解
s = [[0 if i != j else stone[i] for i in xrange(N)] for j in xrange(N)] # s[i][j]代表合并i到j后生成的值
for l in xrange(1, N): # 循环N-1次, 每次得到长度为l+1的石头堆的最优解
for i in xrange(N-l):
j = i + l # 计算当前尾部j
p[i][j] = None
for k in xrange(i, j):
if p[i][j] == None:
s[i][j] = s[i][k] + s[k+1][j]
p[i][j] = p[i][k] + p[k+1][j] + s[i][j]
else:
p[i][j] = min(p[i][j], p[i][k] + p[k+1][j] + s[i][j])
return p[0][N-1] # p[0][N-1]代表合并0到N-1的最优解,即为答案