leetcode刷题记录(16)-中等

1.二叉树的右视图

题目:给定一棵二叉树,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。

思路:可以用层序遍历的方式,将树转成二维数组,然后取每层的最后一个节点

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var rightSideView = function(root) {
  const res = [];
  if (!root) return res;
  const stack = [root];
  while (stack.length) {
    res.push(stack.map((i) => i.val));
    const temp = [];
    for (const item of stack) {
      if (item.left) {
        temp.push(item.left);
      }
      if (item.right) {
        temp.push(item.right);
      }
    }
    stack.splice(0, Infinity, ...temp);
  }
  return res.map((item) => item.pop());
};

也可以在遍历节点的时候记录当前节点的层数,然后将结果放入一个数组里,将层数作为下标

/**
 * Definition for a binary tree node.
 * function TreeNode(val) {
 *     this.val = val;
 *     this.left = this.right = null;
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var rightSideView = function(root) {
  const res = [];
  const search = (root, level) => {
    if (!root) return;
    if (res[level] === undefined) {
      res[level] = root.val;
    }
    search(root.right, level + 1);
    search(root.left, level + 1);
  };
  search(root, 0);
  return res;
};

2.岛屿数量

题目:

给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。

岛屿总是被水包围,并且每座岛屿只能由水平方向或竖直方向上相邻的陆地连接形成。

此外,你可以假设该网格的四条边均被水包围

思路:深度优先遍历,然后将遍历过的岛屿修改为其他字符,这样遍历的次数就是岛屿的数量了

/**
 * @param {character[][]} grid
 * @return {number}
 */
var numIslands = function(grid) {
  const h = grid.length;
  if (!h) return 0;
  const w = grid[0].length;
  let count = 0;
  const dep = (i, j) => {
    if (i >= h || i < 0) return;
    if (j >= w || j < 0) return;
    if (grid[i][j] !== "1") return;
    grid[i][j] = "*";
    dep(i, j + 1);
    dep(i, j - 1);
    dep(i + 1, j);
    dep(i - 1, j);
  };
  for (let i = 0; i < h; i++) {
    for (let j = 0; j < w; j++) {
      if (grid[i][j] == "1") {
        count++;
        dep(i, j);
      }
    }
  }

  return count;
};

3.数字范围按位与

题目:给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点)。

思路:先排除特殊清理。如果两个数字的二进制字符串长度不一样,那么结果肯定是0


/**
 * @param {number} m
 * @param {number} n
 * @return {number}
 */
var rangeBitwiseAnd = function(m, n) {
    if(m.toString(2).length != n.toString(2).length) return 0
    var res = m;
    for(var i=m+1;i<=n;i++){
        res &= i;
    }
    return res
};

4.课程表

题目:

你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。

在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]

给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?

思路:记录某个课程和它的前置课程,然后检查前置课程的前置课程是否有该课程(就是形成了环),如果没有说明可以修完,有环说明不能修完

/**
 * @param {number} numCourses
 * @param {number[][]} prerequisites
 * @return {boolean}
 */
var canFinish = function(numCourses, prerequisites) {
  const map = new Map();
  const isCircle = (cur, pre) => {
    const stack = [cur];
    while (stack.length) {
      const item = stack.pop();
      if (map.get(item)) {
        if (map.get(item).includes(pre)) return true;
        stack.push(...map.get(item));
      }
    }
    return false;
  };
  for (const [cur, pre] of prerequisites) {
    if (isCircle(cur, pre)) return false;
    if (map.get(pre)) {
      map.get(pre).push(cur);
    } else {
      map.set(pre, [cur]);
    }
  }

  return true;
}

也可以用拓扑排序。记录所有的课程,以及它们的前置课程的数量。某个课程的前置课程数量为0,说明可以休这门课,然后再解锁以这门课作为前置课程的课


/**
 * @param {number} numCourses
 * @param {number[][]} prerequisites
 * @return {boolean}
 */
var canFinish = function(numCourses, prerequisites) {
  const inDegree = new Array(numCourses).fill(0); // 入度数组
  const map = {}; // 邻接表
  for (let i = 0; i < prerequisites.length; i++) {
    const [cur, pre] = prerequisites[i];
    inDegree[cur]++; // 求课的初始入度值
    if (map[pre]) {
      // 当前课已经存在于邻接表
      map[pre].push(cur); // 添加依赖它的后续课
    } else {
      // 当前课不存在于邻接表
      map[pre] = [cur];
    }
  }
  const queue = [];
  for (let i = 0; i < inDegree.length; i++) {
    // 所有入度为0的课入列
    if (inDegree[i] == 0) queue.push(i);
  }
  let count = 0;
  while (queue.length) {
    const selected = queue.shift(); // 当前选的课,出列
    count++; // 选课数+1
    const toEnQueue = map[selected]||[]; // 获取这门课对应的后续课
    for (const item of toEnQueue) {
      inDegree[item]--;
      if (!inDegree[item]) {
        queue.push(item);
      }
    }
  }
  return count == numCourses; // 选了的课等于总课数,true,否则false
};

5.实现Trie(前缀树)

题目:实现一个 Trie (前缀树),包含 insertsearch, 和 startsWith 这三个操作。

思路:用一个嵌套的对象记录单词,每个字符作为一级,并且记录末尾的字符

/**
 * Initialize your data structure here.
 */
var Trie = function() {
 this.root = {}
};

/**
 * Inserts a word into the trie. 
 * @param {string} word
 * @return {void}
 */
Trie.prototype.insert = function(word) {
    let node = this.root
    for (const c of word) {
      if (!node[c]) node[c] = {}
      node = node[c]
    }
    node.isWord = true

};

/**
 * Returns if the word is in the trie. 
 * @param {string} word
 * @return {boolean}
 */
Trie.prototype.search = function(word) {
    const node = this.traverse(word)
    return !!node && !!node.isWord
};

/**
 * Returns if there is any word in the trie that starts with the given prefix. 
 * @param {string} prefix
 * @return {boolean}
 */
Trie.prototype.startsWith = function(prefix) {
    return !!this.traverse(prefix)
};
Trie.prototype.traverse=function(word) {
    let node = this.root
    for (const c of word) {
      node = node[c]
      if (!node) return null
    }
    return node
  }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值