这周的双周赛玩脱了,完全脱离状态,只做了 1 道题,其他题目都飞了,整个做完状态就是懒得看了,睡觉为先。
图 1:第 21 场双周赛排名 |
---|
Q1:上升下降字符串
这一题因为题目的规模很小,所以可以直接暴力解答(如果规模上来了,估计我也是要跪的)
[[email protected]]# cat Q1.go
func sortString(s string) string {
var (
i, num int
length = len(s)
count = make([]int, 26)
rst = make([]uint8, length)
)
for i = 0; i < length; i++ {
count[s[i]-'a']++
}
for num < length {
for i = 0; i < 26; i++ {
if count[i] > 0 {
rst[num] = uint8('a' + i)
num++
}
count[i]--
}
for i = 25; i >= 0; i-- {
if count[i] > 0 {
rst[num] = uint8('a' + i)
num++
}
count[i]--
}
}
return string(rst)
}
Q2:每个元音包含偶数次的最长子字符串
这一题是坑,其实很多人吐槽第二和第四的位置交换了,(确实我也是因为在这道题浪费了太多的时间,从而导致后面状态下滑了,因为我一直觉得我就要做出来了)。
后面来反思一下这道题,其实还是有些难度的,然后学习了一下人家的题解发现这是一个自己不知道的方式:状态压缩(似乎之前见过?没印象),然后问题就变得容易理解了(果然,还是需要学习一个)。
这里的做法就是找到相同状态(例如都是多了一个 e)的下标位置,因为这两个位置都是都是多了一个e,那么他们之间的子字符串就刚刚好所有的字符都是偶数的。然后求他们的最大差值就是结果了:
[[email protected]]# cat Q2.go
var target = map[uint8]int{
'a': 1,
'e': 2,
'i': 4,
'o': 8,
'u': 16,
}
func findTheLongestSubstring(s string) int {
var (
i, curr, rst, st int
ok bool
length = len(s)
status = make([]int, 32)
)
for i = 0; i < 32; i++ {
status[i] = math.MaxInt32
}
status[0] = -1
for i = 0; i < length; i++ {
if st, ok = target[s[i]]; ok {
curr ^= st
}
if status[curr] == math.MaxInt32 {
status[curr] = i
} else {
rst = max(rst, i-status[curr])
}
}
return rst
}
Q3:二叉树中的最长交错路径
这道题我在解答的时候用了递归,然后毫无疑问,在一个大规模的 case 下超时了。
图 2:Q3 大规模 Case 超时 |
---|
现在有宽松的时间让我重构一番,其实这不用那么麻烦,用 BFS 和 DFS 都可以,只需要维护每个节点在左遍历和右遍历的时候的最大值就可以了,我这里用了一个 BFS:
[[email protected]]# cat Q3.go
type obj struct {
node *TreeNode
left int
right int
}
func longestZigZag(root *TreeNode) int {
var (
rst int
curr obj
l = list.New()
)
if root == nil {
return 0
}
l.PushBack(obj{
node: root,
left: 0,
right: 0,
})
for l.Len() != 0 {
curr = l.Remove(l.Front()).(obj)
if curr.node.Left != nil {
l.PushBack(obj{
node: curr.node.Left,
left: curr.right + 1,
right: 0,
})
} else {
if curr.right > rst {
rst = curr.right
}
}
if curr.node.Right != nil {
l.PushBack(obj{
node: curr.node.Right,
left: 0,
right: curr.left + 1,
})
} else {
if curr.left > rst {
rst = curr.left
}
}
}
return rst
}
Q4:二叉搜索子树的最大键值和
这道题其实是很简单的,但是,因为我的粗心,对于 BST 的判断,我只判断了是否大于 left.Val 和小于 right.Val,其实应该返回 left.Max 和 right.Min,因为对于这点没有把握好,所以导致一直出错:
图 3:一直出错的 Q4 |
---|
其实这道题就是可以简单的递归,求子树是不是 BST:
- 如果是,判断是否可以和当前的 root 组成更大的 BST,然后分别求和
- 如果不是,那么就求子树的最大 BST 和
[[email protected]]# cat Q4.go
func maxSumBST(root *TreeNode) (rst int) {
isBST(root, &rst)
return rst
}
func isBST(root *TreeNode, maxSum *int) (is bool, sum, minVal, maxVal int) {
if root == nil {
return true, 0, math.MaxInt32, math.MinInt32
}
leftIs, leftSum, leftMin, leftMax := isBST(root.Left, maxSum)
rightIs, rightSum, rightMin, rightMax := isBST(root.Right, maxSum)
if leftIs && rightIs {
if root.Val > leftMax && root.Val < rightMin {
if root.Left == nil {
leftMin = root.Val
}
if root.Right == nil {
rightMax = root.Val
}
rootSum := root.Val + leftSum + rightSum
if rootSum > *maxSum {
*maxSum = rootSum
}
return true, rootSum, leftMin, rightMax
}
return false, max(leftSum, rightSum), math.MaxInt32, math.MinInt32
} else {
return false, max(leftSum, rightSum), math.MaxInt32, math.MinInt32
}
}
func max(a, b int) int {
if a > b {
return a
}
return b
}