【LeetCode】每日一题 面试题 17.25. 单词矩阵

91 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第15天,点击查看活动详情

[面试题 17.25. 单词矩阵](leetcode.cn/problems/ma…)

给定一份单词的清单,设计一个算法,创建由字母组成的面积最大的矩形,其中每一行组成一个单词(自左向右),每一列也组成一个单词(自上而下)。不要求这些单词在清单里连续出现,但要求所有行等长,所有列等高。

如果有多个面积最大的矩形,输出任意一个均可。一个单词可以重复使用。

「示例1:」
输入: ["this", "real", "hard", "trh", "hea", "iar", "sld"]
输出:
[   "this",   "real",   "hard"]
「示例2:」
输入: ["aa"]
输出: ["aa","aa"]
「提示:」
words.length <= 1000
words[i].length <= 100
数据保证单词足够随机

解题思路

思路:
1.如何判断字符串是否能够组成矩形
2.如何保存能够组成矩形的字符串,并进行是否最大的判断
方法:
1.用字典树判断当前字符串的字符结点是否为字典树的结点
2.判断当前字符串所有结点是否都为字典树的叶子结点,如果是,则能组成矩形,并进行是否最大的判断

代码实现

class Trie {
  constructor() {
    this.isLeaf = false
    this.childs = []
  }
}
/**
 * @param {string[]} words
 * @return {string[]}
 */
var maxRectangle = function (words) {
  // 构造字典树
  const root = new Trie()
  for (const str of words) {
    let node = root
    for (const c of str) {
      const index = c.charCodeAt() - 'a'.charCodeAt()
      if (!node.childs[index]) {
        node.childs[index] = new Trie()
      }
      node = node.childs[index]
    }
    node.isLeaf = true
  }
​
  const map = new Map()
  let ans = []
  let maxArea = 0
  let maxLength = 0
  for (const w of words) {
    const len = w.length
    maxLength = Math.max(maxLength, len)
    if (!map.has(len)) map.set(len, new Set())
    map.get(len).add(w)
  }
​
  for (const [key, set] of map) {
    backtracking(set, [], key)
  }
  return ans
​
  // 回溯填入单词
  function backtracking(set, path, len) {
    if (len * maxLength <= maxArea) return
    if (path.length > maxLength) return
    for (const str of set) {
      path.push(str)
      const res = isValid(path)
      if (res[0]) {
        const area = path.length * path[0].length
        if (res[1] && area > maxArea) {
          maxArea = area
          ans = path.slice()
        }
        backtracking(set, path, len)
      }
      path.pop()
    }
  }
​
  // 校验填入的单词是否合法
  function isValid(input) {
    let allLeaf = true
    const m = input.length
    const n = input[0].length
    // 横向的单词都是自己填的,只需要校验每列的单词就行了
    for (let j = 0; j < n; j++) {
      let node = root
      for (let i = 0; i < m; i++) {
        const index = input[i][j].charCodeAt() - 'a'.charCodeAt()
        if (!node.childs[index]) return [false, false]
        node = node.childs[index]
      }
      if (!node.isLeaf) allLeaf = false
    }
    return [true, allLeaf]
  }
}

如果你对这道题目还有疑问的话,可以在评论区进行留言;