LeetCode热题100JS(54/100)第十天|124|200|994|207|208
124. 二叉树中的最大路径和
题目链接:124. 二叉树中的最大路径和
难度:困难
刷题状态:1刷
新知识:
解题过程
思考
示例 1:
输入:root = [1,2,3] 输出:6 解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6
没思路,看答案
题解分析
参考题解链接:二叉树中的最大路径和
详细分析如下
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var maxPathSum = function(root) {
let res=-Infinity
//该函数用来求子树最大链(单边)
function dfs(node){
if(!node) return 0
let lval=dfs(node.left)//左子树最大链和
let rval=dfs(node.right)//右子树最大链和
//更新最大路径和
res=Math.max(res,lval+rval+node.val)
//返回最大子树链
return Math.max(0,Math.max(lval,rval)+node.val)
}
dfs(root)
return res
};
手搓答案(无非废话版)
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @return {number}
*/
var maxPathSum = function(root) {
let res=-Infinity
function dfs(node){
if(!node) return 0
let lval=dfs(node.left)
let rval=dfs(node.right)
res=Math.max(res,lval+rval+node.val)
return Math.max(0,Math.max(lval,rval)+node.val)
}
dfs(root)
return res
};
总结
注意dfs函数是求最大子数链和,包括node.val本身
200. 岛屿数量
题目链接:200. 岛屿数量
难度:中等
刷题状态:1刷
新知识:
解题过程
思考
示例 1:
输入:grid = [ ["1","1","1","1","0"], ["1","1","0","1","0"], ["1","1","0","0","0"], ["0","0","0","0","0"] ] 输出:1
图论类型的题,没思路直接看答案
题解分析
参考题解链接:200. 岛屿数量(DFS / BFS)
详细分析如下
/**
* @param {character[][]} grid
* @return {number}
*/
var numIslands = function(grid) {
//dfs函数的作用是把grid[i][j]所在的岛全都变成0
function dfs(grid,i,j){
//注意grid[i][j]必须要放在最后面
if(i<0||i>=grid.length||j<0||j>=grid[0].length||grid[i][j]=='0') return
//1=>0
grid[i][j]='0'
//遍历上下左右
dfs(grid,i-1,j)
dfs(grid,i+1,j)
dfs(grid,i,j-1)
dfs(grid,i,j+1)
}
let count=0
for(let i=0;i<grid.length;i++){
for(let j=0;j<grid[0].length;j++){
if(grid[i][j]=='1'){
dfs(grid,i,j)
count++
}
}
}
return count
};
手搓答案(无非废话版)
/**
* @param {character[][]} grid
* @return {number}
*/
var numIslands = function(grid) {
function dfs(grid,i,j){
if(i<0||i>=grid.length||j<0||j>=grid[0].length||grid[i][j]=='0') return
grid[i][j]='0'
dfs(grid,i-1,j)
dfs(grid,i+1,j)
dfs(grid,i,j-1)
dfs(grid,i,j+1)
}
let count=0
for(let i=0;i<grid.length;i++){
for(let j=0;j<grid[0].length;j++){
if(grid[i][j]=='1'){
dfs(grid,i,j)
count++
}
}
}
return count
};
总结
注意要先判断i,j的范围,再判断是否到边界了,grid[i][j]
994. 腐烂的橘子
题目链接:994. 腐烂的橘子
难度:中等
刷题状态:1刷
新知识:
解题过程
思考
示例 1:
输入:grid = [[2,1,1],[1,1,0],[0,1,1]] 输出:4
没思路,看答案
题解分析
参考题解链接:多源 BFS,附题单(Python/Java/C++/Go/JS/Rust)
详细分析如下
/**
* @param {number[][]} grid
* @return {number}
*/
var orangesRotting = function(grid) {
//m行数,n列数
let m=grid.length,n=grid[0].length
//新鲜橘子数量
let fresh=0
//腐烂橘子的坐标
let q=[]
for(let i=0;i<m;i++){
for(let j=0;j<n;j++){
if(grid[i][j]==1){
fresh++
}else if(grid[i][j]==2){
q.push([i,j])
}
}
}
let res=0
//如果q为0了,说明所有临近的橘子都被遍历过了
//如果此时还有fresh的橘子,说明,不会全部腐烂
while(fresh&&q.length){
res++//经过一分钟
//存q
let tmp=q
q=[]
for(let [x,y] of tmp){//已经腐烂的橘子
//四个方向上的橘子
for(let [i,j] of [[x-1,y],[x+1,y],[x,y-1],[x,y+1]]){
if(0<=i&&i<m&&0<=j&&j<n&&grid[i][j]==1){
fresh--
grid[i][j]=2//变成腐烂橘子
q.push([i,j])
}
}
}
}
return fresh?-1:res
};
手搓答案(无非废话版)
/**
* @param {number[][]} grid
* @return {number}
*/
var orangesRotting = function(grid) {
let fresh=0,q=[]
for(let i=0;i<grid.length;i++){
for(let j=0;j<grid[0].length;j++){
if(grid[i][j]==1){
fresh++
}else if(grid[i][j]==2){
q.push([i,j])
}
}
}
let res=0
while(fresh&&q.length){
res++
let tmp=q
q=[]
for(let [x,y] of tmp){
for(let [i,j] of [[x-1,y],[x+1,y],[x,y-1],[x,y+1]]){
if(i>=0&&i<grid.length&&j>=0&&j<grid[0].length&&grid[i][j]==1){
fresh--
grid[i][j]=2
q.push([i,j])
}
}
}
}
return fresh?-1:res
};
总结
注意fresh和q这两个变量设置的意义和作用,本题用的是BFS方法
207. 课程表
题目链接:207. 课程表
难度:中等
刷题状态:1刷
新知识:
解题过程
思考
示例 1:
输入:numCourses = 2, prerequisites = [[1,0]] 输出:true 解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。
图论类型的题,没思路直接看答案
题解分析
参考题解链接:课程表(拓扑排序:入度表BFS法 / DFS法,清晰图解)
详细分析如下
/**
* @param {number} numCourses
* @param {number[][]} prerequisites
* @return {boolean}
*/
var canFinish = function (numCourses, prerequisites) {
//用于存储每个课程的 入度 信息
let inDegree=Array(numCourses).fill(0)
//map用来存学完pre[1]才能学习pre[0]
let map=new Map()
for(let pre of prerequisites){
//到pre[0]的路径+1
inDegree[pre[0]]++
//如果map里面没有起点pre[1],就存一个新的起点
if(!map.has(pre[1])){
map.set(pre[1],[pre[0]])
}else{
//如果有的话说明有共同起点,push到pre[1]那一项里面
let arr=map.get(pre[1])
arr.push(pre[0])
map.set(pre[1],arr)
}
}
let q=[]
for(let i=0;i<numCourses;i++){
//如果入度为0,说明现在可以学习,把这些课程加入q
if(inDegree[i]==0) q.push(i)
}
let num=numCourses
while(q.length>0){
//获取q的第一个元素
let tmp=q.shift()
num--
//现在学完了pre[1],看一下pre[1]学完了能学什么pre[0]
let arr=map.get(tmp)||[]
for(let a of arr){
//把能学的pre[0]入度减1
inDegree[a]--
//如果入度为0,说明下次就可以学了
if(inDegree[a]==0) q.push(a)
}
}
return num?false:true
}
手搓答案(无非废话版)
/**
* @param {number} numCourses
* @param {number[][]} prerequisites
* @return {boolean}
*/
var canFinish = function (numCourses, prerequisites) {
let inDegree=new Array(numCourses).fill(0)
for(let pre of prerequisites) inDegree[pre[0]]++
let map=new Map()
for(let pre of prerequisites){
if(!map.has(pre[1])){
map.set(pre[1],[pre[0]])
}else{
map.get(pre[1]).push(pre[0])
}
}
let num=numCourses,q=[]
for(let i=0;i<num;i++){
if(inDegree[i]==0) q.push(i)
}
while(q.length){
let tmp=q.shift()
num--
let next=map.get(tmp)||[]
for(let n of next){
inDegree[n]--
if(inDegree[n]==0) q.push(n)
}
}
return num?false:true
}
总结
这道题好难啊,,,主要是要设置的存数据的变量很多,注意这里要设置let next=map.get(tmp)||[],如果不存在tmp学完的下一个,要给它赋初值[]
208. 实现 Trie (前缀树)
题目链接:208. 实现 Trie (前缀树)
难度:中等
刷题状态:1刷
新知识:
解题过程
思考
示例:
输入 ["Trie", "insert", "search", "search", "startsWith", "insert", "search"] [[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]] 输出 [null, null, true, false, true, null, true] 解释 Trie trie = new Trie(); trie.insert("apple"); trie.search("apple"); // 返回 True trie.search("app"); // 返回 False trie.startsWith("app"); // 返回 True trie.insert("app"); trie.search("app"); // 返回 True
没思路,看答案
题解分析
参考题解链接:Trie Tree 的实现 (适合初学者)🌳
详细分析如下
var Trie = function() {
this.isEnd=false
this.next={}//用对象来存储子节点,模拟哈希表
};
/**
* @param {string} word
* @return {void}
*/
//插入一个单词到字典树中
Trie.prototype.insert = function(word) {
let node=this
for(let char of word){
//将字符转换为0-25的索引(假设只处理小写字母)
let charCode=char.charCodeAt(0)-97
if(!node.next[charCode]) node.next[charCode]=new Trie()
node=node.next[charCode]
}
node.isEnd=true
};
/**
* @param {string} word
* @return {boolean}
*/
//搜索一个单词是否在字典中
Trie.prototype.search = function(word) {
let node=this
for(let char of word){
let charCode=char.charCodeAt(0)-97
node=node.next[charCode]
if (!node) return false
}
return node.isEnd
};
/**
* @param {string} prefix
* @return {boolean}
*/
//检查是否存在以,给定前缀 ,开头的单词
Trie.prototype.startsWith = function(prefix) {
let node=this
for(let char of prefix){
let charCode=char.charCodeAt(0)-97
node=node.next[charCode]
if(!node) return false
}
return true
};
/**
* Your Trie object will be instantiated and called as such:
* var obj = new Trie()
* obj.insert(word)
* var param_2 = obj.search(word)
* var param_3 = obj.startsWith(prefix)
*/
手搓答案(无非废话版)
var Trie=function(){
this.isEnd=false
this.next={}
}
/**
* @param {string} word
* @return {void}
*/
Trie.prototype.insert=function(word){
let node=this
for(let char of word){
let charCode=char.charCodeAt(0)-97
if(!node.next[charCode]) node.next[charCode]=new Trie()
node=node.next[charCode]
}
node.isEnd=true
}
/**
* @param {string} word
* @return {void}
*/
Trie.prototype.search=function(word){
let node=this
for(let char of word){
let charCode=char.charCodeAt(0)-97
node=node.next[charCode]
if(!node) return false
}
return node.isEnd
}
/**
* @param {string} word
* @return {void}
*/
Trie.prototype.startsWith=function(word){
let node =this
for(let char of word){
let charCode=char.charCodeAt(0)-97
node=node.next[charCode]
if (!node) return false
}
return true
}
总结
函数定义类型的题目,有固定思路