算法
题意理解
一个二维数组,表示树节点之间的连接情况。一个对树结构进行猜测的二维数组,[ui, vi] 表示 ui 为 vi 的父节点。常数 k , 表示猜测中至少有 k 个是正确的,求树满足的结构有几种
思路
- 构建邻接表,表示每个节点之间的连接情况
- 以每个节点为根节点,列举所有的可能性
- 遍历所有的可能性,判断是否满足猜测的结构
- 返回满足猜测条件的树的棵树
解题
const step1 = (edges, guesses, k) => {
const n = edges.length + 1
const graph = new Array(n).fill('').map(() => [])
for (let i = 0; i < edges.length; i++) {
const [u ,v] = edges[i]
graph[u].push(v)
graph[v].push(u)
}
let count = 0
for(let i = 0; i < n; i++) {
const stack = [[i, -1]]
let correctGuesses = 0
while(stack.length) {
const [node, parent] = stack.pop()
// 判断是否符合猜测
for (const [u, v] of guesses) {
if (v === node && u === parent) {
correctGuesses++
}
}
// 继续遍历相邻节点
for(const next of graph[node]) {
if (next !== parent) {
stack.push([next, node])
}
}
}
if (correctGuesses >= k) count++
}
return count
}
优化
- 判断是否符合猜测可以使用哈希表
- 遍历节点使用 dfs
- 保存过已经遍历的点
const step2 = (edges, guesses, k) => {
const n = edges.length + 1
const graph = new Array(n).fill('').map(() => [])
const guessMap = new Map()
// 构造邻接表
for (let i = 0; i < edges.length; i++) {
const [u, v] = edges[i]
graph[u].push(v)
graph[v].push(u)
}
// 构造父子关系哈希表
for (const [u, v] of guesses) {
guessMap.set(v, u)
}
let count = 0
for (let i = 0; i < n; i++) {
let correct = 0
const visited = new Set()
const dfs = (node, parent) => {
visited.add(node)
if (guessMap.get(node) === parent) correct++
// 遍历相邻点
for(const next of graph[node]) {
if (!visited.has(next)) {
dfs(next, node)
}
}
}
dfs(i, -1)
if (correct >= k) count++
}
return count
}
TypeChallenge
实现一个类型 KebabCase<S> ,实现字符串类型驼峰转 KebabCase 写法
思路
- 模板字符串拆解字符
- 使用内置类型
Uncapitalize将剩余字符串首字母转换成小写 - 判断和之前是否一致
- 如果不一致,中间添加
-
解题
type KebabCase<S> = S extends `${infer R}${infer L}`
? L extends UnCapitalize<L>
? `${LowerCase<R>}${UnCapitalize<L>}`
: `${LowerCase<R>}-${UnCapitalize<L>}`
: S