js解leetcode(74)-中等

本文介绍了JavaScript实现LeetCode中的四个算法问题:元音拼写检查器、连续差相同的数字、煎饼排序和翻转二叉树以匹配先序遍历。详细阐述了每个问题的思路和解决方案,包括时间复杂度和空间复杂度分析。
摘要由CSDN通过智能技术生成

1.元音拼写检查器

题目:

在给定单词列表 wordlist 的情况下,我们希望实现一个拼写检查器,将查询单词转换为正确的单词。

对于给定的查询单词 query,拼写检查器将会处理两类拼写错误:

大小写:如果查询匹配单词列表中的某个单词(不区分大小写),则返回的正确单词与单词列表中的大小写相同。
例如:wordlist = ["yellow"], query = "YellOw": correct = "yellow"
例如:wordlist = ["Yellow"], query = "yellow": correct = "Yellow"
例如:wordlist = ["yellow"], query = "yellow": correct = "yellow"
元音错误:如果在将查询单词中的元音(‘a’、‘e’、‘i’、‘o’、‘u’)分别替换为任何元音后,能与单词列表中的单词匹配(不区分大小写),则返回的正确单词与单词列表中的匹配项大小写相同。
例如:wordlist = ["YellOw"], query = "yollow": correct = "YellOw"
例如:wordlist = ["YellOw"], query = "yeellow": correct = "" (无匹配项)
例如:wordlist = ["YellOw"], query = "yllw": correct = "" (无匹配项)
此外,拼写检查器还按照以下优先级规则操作:

当查询完全匹配单词列表中的某个单词(区分大小写)时,应返回相同的单词。
当查询匹配到大小写问题的单词时,您应该返回单词列表中的第一个这样的匹配项。
当查询匹配到元音错误的单词时,您应该返回单词列表中的第一个这样的匹配项。
如果该查询在单词列表中没有匹配项,则应返回空字符串。
给出一些查询 queries,返回一个单词列表 answer,其中 answer[i] 是由查询 query = queries[i] 得到的正确单词。

思路:

符合条件的有三种可能:
1.当前单词在列表里;
2.列表转成小写字符,当前单词忽略大小写之后,在小写的列表里;
3.所有单词模糊元音字符,当前单词也忽略,在忽略元音的列表里;

但是,替换的单词是原列表的单词,
所以,用3个map分别记录原单词、全小写的单词、元音模糊单词的字符第一次出现的下标。三个map查找的优先级是先找原单词,再找小写单词,再找元音模糊单词。
对于元音字符,可以用正则替换成特殊字符,然后将新的字符作为key存储
如果三个map里面都找不到,就返回空字符串。
两个map也可以,不过数组的查找比map查找更消耗时间
时间复杂度O(n),空间复杂度O(n)

/**
 * @param {string[]} wordlist
 * @param {string[]} queries
 * @return {string[]}
 */
const transform = (s) => {
  return s.toLowerCase().replace(/[aeiou]/g, "*");
};
var spellchecker = function (wordlist, queries) {
  const map2 = new Map();
  const map3 = new Map();
  const map = new Map();
  const l = wordlist.length;
  for (let i = 0; i < l; i++) {
    map.set(wordlist[i], i);
    if (!map2.has(wordlist[i].toLowerCase())) {
      map2.set(wordlist[i].toLowerCase(), i);
    }
    const newWord = transform(wordlist[i]);
    if (!map3.has(newWord)) {
      map3.set(newWord, i);
    }
  }
  return queries.map((item) => {
    return (
      wordlist[
        map.get(item) ?? map2.get(item.toLowerCase()) ?? map3.get(transform(item))
      ] ?? ""
    );
  });
};

2.连续差相同的数字

题目:

返回所有长度为 n 且满足其每两个连续位上的数字之间的差的绝对值为 k 的 非负整数 。

请注意,除了 数字 0 本身之外,答案中的每个数字都 不能 有前导零。例如,01 有一个前导零,所以是无效的;但 0 是有效的。

你可以按 任何顺序 返回答案。

思路:递归处理。第一个数字不能是0,所以先循环从1-9取第一个数字,然后在递归函数里记录之前的取数结果以及剩余能取的数字的数量。

时间复杂度O(n),空间复杂度O(n)

/**
 * @param {number} n
 * @param {number} k
 * @return {number[]}
 */
var numsSameConsecDiff = function(n, k) {
  const res = [];
  const dfs = (preN, s) => {
    if (preN >= 10 || preN < 0) return;
    if (s.length === n) {
      res.push(Number(s));
      return;
    }
    dfs(preN + k, `${s}${preN + k}`);
    if (!k) return;
    dfs(preN - k, `${s}${preN - k}`);
  };
  for (let i = 1; i <= 9; i++) {
    dfs(i, `${i}`);
  }
  return res;
};

3.煎饼排序

题目:

给你一个整数数组 arr ,请使用 煎饼翻转 完成对数组的排序。

一次煎饼翻转的执行过程如下:

选择一个整数 k ,1 <= k <= arr.length
反转子数组 arr[0...k-1](下标从 0 开始)
例如,arr = [3,2,1,4] ,选择 k = 3 进行一次煎饼翻转,反转子数组 [3,2,1] ,得到 arr = [1,2,3,4] 。

思路:对于长度为l的数组,如何通过翻转进行排序呢?因为每次翻转的是1-k的数字,所以为了让之前排好序的数字不受后面的翻转的影响,可以将数字先放到最后

即将数字倒序排列,最后一次翻转得到结果,

对于长度为l的数组,先找到最小值的下标index,然后翻转前index个数字,再翻转前l个数字,即可将当前最小的数字翻转到最后

然后进行l-1长度时候的处理。

时间复杂度O(nlogn),空间复杂度O(n)。最不理想的时候,需要翻转2n+1次,

/**
 * @param {number[]} arr
 * @return {number[]}
 */
var pancakeSort = function(arr) {
  const res = [];
  const dfs = (len) => {
    if (len < 2) return;
    let min = Infinity;
    let index;
    for (let i = 0; i < len; i++) {
      if (arr[i] < min) {
        index = i;
        min = arr[i];
      }
    }
    if (index === len - 1) {
      dfs(len - 1);
      return;
    }

    if (index === 0) {
      res.push(len);
      for (let i = 0; i < len / 2; i++) {
        [arr[i], arr[len - 1 - i]] = [arr[len - 1 - i], arr[i]];
      }
      dfs(len - 1);
      return;
    }
    for (let i = 0; i <= index / 2; i++) {
      [arr[i], arr[index - i]] = [arr[index - i], arr[i]];
    }
    for (let i = 0; i < len / 2; i++) {
      [arr[i], arr[len - 1 - i]] = [arr[len - 1 - i], arr[i]];
    }
    res.push(index + 1);
    res.push(len);
    dfs(len - 1);
  };
  dfs(arr.length);
  res.push(arr.length);
  return res;
};

4.翻转二叉树以匹配先序遍历

题目:

给你一棵二叉树的根节点 root ,树中有 n 个节点,每个节点都有一个不同于其他节点且处于 1 到 n 之间的值。

另给你一个由 n 个值组成的行程序列 voyage ,表示 预期 的二叉树 先序遍历 结果。

通过交换节点的左右子树,可以 翻转 该二叉树中的任意节点。例,翻转节点 1 的效果如下:


请翻转 最少 的树中节点,使二叉树的 先序遍历 与预期的遍历行程 voyage 相匹配 。 

如果可以,则返回 翻转的 所有节点的值的列表。你可以按任何顺序返回答案。如果不能,则返回列表 [-1]。

思路:用一个变量记录当前遍历的节点数,然后对二叉树进行先序遍历,对于任意一个节点,判断左右节点的情况,如果左右节点非空,且不等于当前的voyage[i],说明无法通过交换得到结果,所以返回-1.如果可以交换,就先交换然后继续遍历

时间复杂度O(n),空间复杂度O(h)

var flipMatchVoyage = function(root, voyage) {
  const res = [];
  let flag = true;
  if (!root) return voyage.length ? [-1] : [];
  if (root.val !== voyage[0]) return [-1];
  let i = 1;
  const dfs = (root) => {
    if (!root) return;

    if (!root.left && !root.right) return;

    if (!root.left) {
      if (root.right.val === voyage[i]) {
        i++;
        dfs(root.right);
      } else {
        flag = false;
      }
    } else {
      if (root.left.val === voyage[i]) {
        i++;
        dfs(root.left);
        if (!root.right) return;
        if (root.right.val !== voyage[i]) {
          flag = false;
        } else {
          i++;
          dfs(root.right);
        }
      } else {
        if (!root.right) {
          flag = false;
        } else if (root.right.val !== voyage[i]) {
          flag = false;
        } else {
          [root.left, root.right] = [root.right, root.left];
          res.push(root.val);
          i++;
          dfs(root.left);
          if (root.right.val !== voyage[i]) {
            flag = false;
          } else {
            i++;
            dfs(root.right);
          }
        }
      }
    }
  };
  dfs(root);
  return flag ? res : [-1];
};

5.最接近原点的k个点

题目:

我们有一个由平面上的点组成的列表 points。需要从中找出 K 个距离原点 (0, 0) 最近的点。

(这里,平面上两点之间的距离是欧几里德距离。)

你可以按任何顺序返回答案。除了点坐标的顺序之外,答案确保是唯一的。

思路:每个点映射出对应的下标以及对应到原点的距离,通过原点距离进行排序,然后再截取前k个距离,返回对应下标的点

时间复杂度O(nlogn),空间复杂度O(logn)

/**
 * @param {number[][]} points
 * @param {number} k
 * @return {number[][]}
 */
var kClosest = function(points, k) {
  const dis = points.map((item, index) => {
    return [Math.pow(item[0], 2) + Math.pow(item[1], 2), index];
  });
  dis.sort((a, b) => a[0] - b[0]);
  return dis.slice(0, k).map((item) => points[item[1]]);
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值