问:
- 给定一棵二叉树的头结点head,已知所有节点值都不一样。返回其中最大符合搜索二叉树的最大拓扑结构的节点个数
- 给定一个长度为偶数的数组arr,长度记为2 * N,前N个当做左部分,后N个为右部分。arr就可以表示为[L1,L2,L3...LN,R1,R2,R3...RN]。将数组调整为[R1,L1,R2,L2,R3,L3...RN,LN],要求空间复杂度O(1)
解:
- 创建一个map,key是一个节点,value存放的是对于此节点来说,左右子树分别贡献了多少符合条件的节点。当递归来到一个节点的时候,遍历左子树的右边界,查询是否有不合符条件的节点,若有就记录这个节点。同样遍历右子树的左边界,查询是否有不符合条件的节点,有则记录。当获取到不符合条件的节点,意味着左右子树满足二叉搜索结构的路径走到不符合节点时就会断掉。所以左子树的右边界沿途节点的贡献值把不符合节点的贡献值减去。右子树的左边界沿途节点的贡献值把不符合节点的贡献值减去。这样就更新了左子树的贡献值和右子树的贡献值,存入map。用一个全局变量max去判断最大节点数即可。
function getMax(head) {
const map = new Map()
let max = 1
function getRes(node) {
if (!node) return
getRes(node.left)
getRes(node.right)
let tempLeft = node.left
let tempRight = node.right
const breakLeft = {
node: null,
value: 0
}
const breakRight = {
node: null,
value: 0
}
// 判断左树的右边界是否有不满足条件的
while (tempLeft) {
if (tempLeft.value < node.value) {
tempLeft = tempLeft.right
} else {
// 有某个节点不满足二叉搜索树
breakLeft.node = tempLeft
breakLeft.value = map.get(tempLeft).all
map.delete(tempLeft)
break
}
}
// 判断右树的左边界是否有不满足条件的
while (tempRight) {
if (tempRight.value > node.value) {
tempRight = tempRight.left
} else {
breakRight.node = tempRight
breakRight.value = map.get(tempRight).all
map.delete(tempRight)
break
}
}
if (tempLeft) {
tempLeft = node.left
while (tempLeft !== breakLeft.node) {
const preValue = map.get(tempLeft)
map.set(tempLeft, {
l: preValue.l,
r: preValue.r - breakLeft.value,
all: preValue.l + preValue.r - breakLeft.value + 1
})
tempLeft = tempLeft.right
}
}
if (tempRight) {
tempRight = node.right
while (tempRight !== breakRight.node) {
const preValue = map.get(tempRight)
map.set(tempRight, {
l: preValue.l - breakRight.value,
r: preValue.r,
all: preValue.l + preValue.r - breakRight.value + 1
})
tempRight = tempRight.left
}
}
const l = map.has(node.left) ? map.get(node.left).all : 0
const r = map.has(node.right) ? map.get(node.right).all : 0
map.set(node, {
l,
r,
all: l + r + 1
})
max = Math.max(max, l + r + 1)
}
getRes(head)
return max
}
- 完美洗牌算法
function shuffleCards(arr) {
let handleLength = arr.length
while (handleLength > 0) {
// 剩余要处理的个数,最多是3的几次方 - 1
const k = getK(handleLength)
// 这一批处理多少个数
const temp = 3 ** k - 1
// 从何处开始处理
const start = arr.length - handleLength
const split = Math.floor(((arr.length - handleLength) + arr.length - 1) / 2)
reverse(temp / 2 + start, split + temp / 2, split)
wash(k, start, arr)
handleLength -= temp
}
return arr
function getK(length) {
let k = 1
while (3 ** (k + 1) - 1 < length) {
k++
}
return k
}
function wash(k, start, arr) {
let idx = 1
while (idx <= k) {
const cur = 3 ** (idx - 1) - 1 + start
const info = {
value: arr[cur],
idx: cur
}
arr[info.idx] = null
while (info.value) {
const pos = getPosition(info.idx - start, 3 ** k -1) + start
if (arr[pos]) {
const temp = arr[pos]
arr[pos] = info.value
debugger
info.value = temp
info.idx = pos
} else {
arr[pos] = info.value
info.value = null
info.idx = -1
}
}
idx++
}
}
function reverse(left, right, split) {
let l1 = left
let r1 = split
while (l1 < r1) {
[arr[l1], arr[r1]] = [arr[r1], arr[l1]]
l1++
r1--
}
let l2 = split + 1
let r2 = right
while (l2 < r2) {
[arr[l2], arr[r2]] = [arr[r2], arr[l2]]
l2++
r2--
}
let l3 = left
let r3 = right
while (l3 < r3) {
[arr[l3], arr[r3]] = [arr[r3], arr[l3]]
l3++
r3--
}
}
function getPosition(idx, n) {
n = n / 2
if (idx < n) {
return 2 * idx + 1
}
return 2 * (idx - n)
}
}