挑战 - 每日系列(Algorithm + TypeChallenge)

53 阅读2分钟

算法

2581. 统计可能的树根数目

题意理解

一个二维数组,表示树节点之间的连接情况。一个对树结构进行猜测的二维数组,[ui, vi] 表示 uivi 的父节点。常数 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