继续第二期,这部分的三道题变得比较复杂了。
Qus4 游历魔法王国
试题描述
魔法王国一共有n
个城市,编号为0~n-1
号,n
个城市之间的道路连接起来恰好构成一棵树。
小易现在在0
号城市,每次行动小易会从当前所在的城市走到与其相邻的一个城市,小易最多能行动L
次。
如果小易到达过某个城市就视为小易游历过这个城市了,小易现在要制定好的旅游计划使他能游历最多的城市,请你帮他计算一下他最多能游历过多少个城市(注意0号城市已经游历了,游历过的城市不重复计算)。
输入描述:
输入包括两行,第一行包括两个正整数
n(2 ≤ n ≤ 50)
和L(1 ≤ L ≤ 100)
,表示城市个数和小易能行动的次数。
第二行包括n-1
个整数parenti, 对于每个合法的i(0 ≤ i ≤ n - 2)
,在(i+1)
号城市和parent[i]
间有一条道路连接。
输出描述:
输出一个整数,表示小易
最多
能游历的城市数量。
示例1
输入
5 2
0 1 2 3输出
3
试题分析
试题最后抽象成求树的最大深度。
输入描述中第二行 第二行包括n-1
个整数parent[i](0 ≤ parent[i] ≤ i)
, 对于每个合法的i(0 ≤ i ≤ n - 2)
,在(i+1)
号城市和parent[i]
间有一条道路连接,绕了半天,其实是描述树的形状。
例如测试用例:
10 10
0 3 1 3 0 5 2 7 5
对应的关系如下:
Tables | Col 1 | Col 2 | Col 3 | Col 4 | Col 5 | Col 6 | Col 7 | Col 8 | Col 9 |
---|---|---|---|---|---|---|---|---|---|
子节点(i) | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
父节点(parent[i]) | 0 | 3 | 1 | 3 | 0 | 5 | 2 | 7 | 5 |
生成的树:
树的结构有了之后,就只需要根据树的最大深度depth
与可走的最大步数L
之间的关系来判断最终的游历城市数量。
- 当
depth ≥ L
时,那么能够游历的城市数即L + 1
(因为出发位置在得0号城市,算是已经游历的城市); - 当
depth < L
时,即需要走重复的路。显而易见,返回需要走两遍相同的路径。最优化的行走方案是将旅程分为两个部分,一个部分为走到最大深度depth
,另一部分为走重复路的短路径(L-depth)/2
(即除了树的大深度外的步数,由于折返故除以2)。
代码实现
1 | function main(argument) { |
反思
- 代码中有一项未判断,即当步数
L>(depth + (L-depth)/2)
时,部署应该为城市数n
; - 在生成树的过程中,由于遍历过程中可能部分节点在未生成时引用会出现
undefined
问题,故引入判断,在第15行处再循环一次; - 第20行处实用了
ES6
中的扩展运算符( ... )
,在学习ES6
时再继续详细解答; - 其实对于生成树与计算最大深度还是不太明白,该抽时间补一补数据结构了。
Qus5 重排数列
试题描述
小易有一个长度为N的正整数数列A = {A[1], A[2], A[3]..., A[N]}
。
牛博士给小易出了一个难题:
对数列A
进行重新排列,使数列A满足所有的A[i] * A[i + 1](1 ≤ i ≤ N - 1)
都是4
的倍数。
小易现在需要判断一个数列是否可以重排之后满足牛博士的要求。
输入描述:
输入的第一行为数列的个数
t(1 ≤ t ≤ 10)
,
接下来每两行描述一个数列A
,第一行为数列长度n(1 ≤ n ≤ 10^5)
第二行为n
个正整数A[i](1 ≤ A[i] ≤ 10^9)
输出描述:
对于每个数列输出一行表示是否可以满足牛博士要求,如果可以输出
Yes
,否则输出No
。
示例1
输入
2
3
1 10 100
4
1 2 3 4输出
Yes
No
试题分析
根据题意,将数列A
中的数字分为三类:
n4 : 可以被4整除的数
n2 : 可以被2整除但不可以被4整除的数
n1 : 不可以被2整除的数
那么如果要满足题目要求即A[i] * A[i + 1](1 ≤ i ≤ N - 1)
都是4
的倍数,则必须以下两种情况:
- 数字
n1
的两侧都要有n4
(数列第一个或最后一个只需满足一侧存在n4
即可); - 数字
n2
的两侧要存在n2
或者n4
;
那么对条件进行简化,数组A
可能出现的情况:
n4 > = n1
—— 满足题目要求;n4 = n1 - 1 && n4 + n1 = A.length
—— 数列第一个与最后一个均为n1
,满足题目要求;n4 < n1 - 1
—— 不满足
这样就很清晰了,详情见代码实现
代码实现
1 | function main(argument) { |
反思
- 最开始的思路是按照题意,数列中的所有数字互相相乘,得出新的数列。判断新的数列中的数组是否能被4整除,如果得到的结果大于原数组length - 1 即满足条件,这样能通过最开始的两组数列的测验,因为开始的数列相对比较短(4个以下);
- 写了一个取模的函数,参数采用
json
格式;
Qus6 最长公共子括号序列
试题描述
一个合法
的括号匹配序列被定义为:
- 空串
""
是合法的括号序列 - 如果
"X"
和"Y"
是合法的序列,那么"XY"
也是一个合法的括号序列 - 如果
"X"
是一个合法的序列,那么"(X)"
也是一个合法的括号序列 - 每个合法的括号序列都可以由上面的规则生成
例如""
,"()"
, "()()()"
, "(()())"
, "(((()))"
都是合法的。
从一个字符串S
中移除零个或者多个字符得到的序列称为S
的子序列。
例如"abcde"
的子序列有"abe"
,""
,"abcde"
等。
定义LCS(S,T)
为字符串S
和字符串T
最长公共子序列的长度,即一个最长的序列W
既是S
的子序列也是T
的子序列的长度。
小易给出一个合法的括号匹配序列S
,小易希望你能找出具有以下特征的括号序列t:
T
跟S
不同,但是长度相同T
也是一个合法的括号匹配序列LCS(S, T)
是满足上述两个条件的T
中最大的
因为这样的T
可能存在多个,小易需要你计算出满足条件的T
有多少个。
如样例所示: S = "(())()"
,跟字符串S
长度相同的合法括号匹配序列有:"()(())"
, "((()))"
, "()()()"
, "(()())"
,其中LCS( "(())()", "()(())" )
为4
,其他三个都为5
,所以输出3
.
输入描述:
输入包括字符串
S
(4 ≤ |S| ≤ 50
,|S|
表示字符串长度),保证S
是一个合法的括号匹配序列。
输出描述:
输出一个正整数,满足条件的
T
的个数。
示例1
输入
(())()
输出
3
试题分析
很容易得出满足LCS(S , T)
最大的S
与T
最长序列W
的长度为S.length - 1
。那么接下来的问题就很容易处理了。
将S
中的任意一个字节抽离出来放到任意一个位置生成新的字符串T
,通过合法性判断与去重,并且去除原字符串,得到的数组长度即为最终结果。
代码实现
1 | function main(str) { |
反思
- 通过数组的
堆栈
方式来判断括号字符串是否合法,主要通过出栈方法array.pop()
方法是否为空来判断(代码37行); - 因为经过遍历去重后的数组,肯定有一个和原数组一样,所以返回最终结果时不需要再对原数组进行去重处理,直接将返回的
length - 1
即最后结果(代码37行); - 第10行的时候,犯了个低级错误,写错变量名,调试了很久才发现。。