834 Sum of Distances in Tree
思路:一颗无向的树有N个节点,分别标记为0,1,2,…N-1,有若干条边。结果返回每个节点到其他节点的路径和。
以上面这棵树为例。从节点0到其他点的路径查找过程是:节点0有两条边分别到达子节点1和子节点2;递归查找节点1(节点1没有子节点),节点2;继续查找节点2的子节点…依次下去。递归每进一层,路径就需要加1。
遍历完节点0以后,再以节点1为根节点,遍历。
时间复杂度O(N*E),E是边的数目。这个思路超时。既然是超时,定是因为有重复计算的。例如遍历边(0,2),之后又遍历了一次(2,0)。但是该怎么合并计算,我没想出来。
学习:接下来的描述,相当于翻译官方解释吧。
用一颗新的树为例子。节点0和节点4是父子关系,也是相邻节点。现在观察一下相邻节点连接后,路径和发生什么变化。
将节点0和节点4的路径断开,得到下图。
记:stsum[0] 表示节点0在节点0子树上的路径和。stsum[4]表示节点4在节点4子树上的路径和。count[0]表示节点0子树的节点数。answer[0]表示节点0在整个树的路径和。answer[4]表示节点4在整个树的路径和。
当节点0和节点4之间加上路径后,answer[0]= stsum[0] + stsum[4] + count[4]。因为节点0到节点4子树上所有点的距离与节点4到节点4子树上所有点的距离都要加1。answer[4]= stsum[4] + stsum[0] + count[0]。而且能得到answer[0]-answer[4]=count[4]-count[0]。
所以得到结论:相邻节点(父子节点)x,y在整个树的路径和是:
a
n
s
w
e
r
[
x
]
−
a
n
s
w
e
r
[
y
]
=
c
o
u
n
t
[
y
]
−
c
o
u
n
t
[
x
]
answer[x] -answer[y] = count[y] - count[x]
answer[x]−answer[y]=count[y]−count[x]。
编码过程:
1 answer[]存储以每个节点为根节点在整个树的路径和;
2 count[] 存储以每个节点为根节点的子树的节点数,初始化每个元素值=1;
3 对某个节点node,dfs后序遍历,先处理子节点,计算每个子节点y的count和stsum,
c
o
u
n
t
[
n
o
d
e
]
+
=
c
o
u
n
t
[
c
h
i
l
d
]
count[node]+=count[child]
count[node]+=count[child],
s
t
s
u
m
[
n
o
d
e
]
+
=
s
t
s
u
m
[
c
h
i
l
d
]
+
c
o
u
n
t
[
c
h
i
l
d
]
stsum[node] +=stsum[child]+count[child]
stsum[node]+=stsum[child]+count[child],当遍历了所有的边以后
a
n
s
w
e
r
[
n
o
d
e
]
=
s
t
s
u
m
[
n
o
d
e
]
answer[node] = stsum[node]
answer[node]=stsum[node];如果我们从节点0开始遍历。这次遍历结束后只有answer[0]是正确的。其他节点都没有遍历完全。
4 再看,上面分析了两个相邻节点(父子节点)的路径和关系。如果有节点parent和子节点child,则有
a
n
s
w
e
r
[
c
h
i
l
d
]
=
a
n
s
w
e
r
[
p
a
r
e
n
t
]
−
c
o
u
n
t
[
c
h
i
l
d
]
+
(
N
−
c
o
u
n
t
[
c
h
i
l
d
]
)
answer[child] = answer[parent] - count[child] + (N - count[child])
answer[child]=answer[parent]−count[child]+(N−count[child]),因为我们已经得到answer[0]的正确结果,可以依据算式计算节点0的子节点的answer。算式中之所以使用count[child]来计算count[parent]:
N
−
c
o
u
n
t
[
c
h
i
l
d
]
)
=
c
o
u
n
t
[
p
r
e
n
t
]
N - count[child])=count[prent]
N−count[child])=count[prent],是因为在上一步的后续遍历过程中,count[parent]的值已经发生变化,不再是parent、child状态下的count
(原文的解释是:count[child]从child得到parent比较容易)。用先序遍历再次遍历树,修改每个子节点的answer,得到最终结果。
代码
301 Remove Invalid Parentheses
思路:最直接的想法:把s中每一个(,)去掉,检查新的字符串是不是有效字符串,如果是则加入到结果集。
这样不符合题意的要求:去掉最少的括号。那么需要计算最少去掉几个左括号,去掉几个右括号,就可以是有效字符串。
在编码过程中注意去重。
代码
学习:可以改进,不再需要判断是否是有效字符串。添加变量open。有效字符的特征是:左括号在前,所以open>0;左右括号个数相同=>open=0;多余的左右括号都去掉了=>leftCount=0 and rightCount=0。
代码