力扣 100-199
101.对称二叉树
//里面设递归函数(l,r)
// 如果l无r有,l有r无 return false
// 如果l值不等于r值 return false
// 如果左右都无,返回true
// outside=递归函数(l.left,r.right)
// inside=递归函数(l.right,r.left)
// 返回inside&&outside
// 外层返回启动函数(root.left,root.right)
var isSymmetric = function (root) {
var compare = function (left, right) {
if ((left && !right) || (!left && right)) {
return false;
} else if (!left && !right) {
return true;
} else if (left.val != right.val) {
return false;
}
//剩下的情况便是两侧有值并且相等,那么就进行下一步递归
return compare(left.left, right.right) && compare(left.right, right.left);
};
return compare(root.left, root.right);
};
102.二叉树的层序遍历
// 特殊!root
// q里存root
// 循环q.length
// 当前层level数组
// 记录q.length(上一层容量)
// for每次shift一个q元素,当前层加入val (如果用pop则先加right再加left)
// 如果元素有left,q里push元素
// 右边同理
// 跳出循环把当前层加入ans
var levelOrder = function (root) {
let ans = [];
if (!root) {
return ans;
}
let q = [root];
while (q.length !== 0) {
// 双层循环,不断加level
let level = [];
// 必须记录q长度,因为长度不固定
let cur = q.length;
for (let i = 0; i < cur; i++) {
// 把节点给拿出来直接.val不要用下标
// 从队列首
let tem = q.shift();
level.push(tem.val);
// if判断有没有tem
if (tem.left) q.push(tem.left);
if (tem.right) q.push(tem.right);
}
ans.push(level);
}
return ans;
};
103.二叉树的锯齿形层序遍历
const zigzagLevelOrder = function (root) {
if (!root) {
return [];
}
let q = [root];
let n = true;
let ans = [];
while (q.length) {
let thisLevel = [];
let thisLevelsize = q.length;
for (let i = 0; i < thisLevelsize; i++) {
let forNode = q.shift();
// 以下为升级
if (n) {
thisLevel.push(forNode.val);
} else {
// 逆序,把当前的q-node加在thisLevel最左边
thisLevel.unshift(forNode.val);
}
// 以上为升级
// 往q中加入下一层,还是跟层序遍历题一样从左往右加
if (forNode.left) {
q.push(forNode.left);
}
if (forNode.right) {
q.push(forNode.right);
}
}
ans.push(thisLevel);
n = !n;
}
return ans;
};
104.二叉树的最大深度
const maxDepth = function (root) {
let ans = 0;
if (!root) return 0;
ans = Math.max(maxDepth(root.left), ans);
ans = Math.max(maxDepth(root.right), ans);
return ans + 1;
};
105.从前序与中序遍历序列构造二叉树
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
// TreeNode题目已给,用treeNode创建节点
// 递归函数buildTree(先序数组preoreder,中序数组inorder)
// *如果先序数组有长度
// 从先序数组shift()第一个值,用TreeNode new出head
// 用head.val加indexOf找出中序数组中的index位
// head.left = 递归函数(先序遍历从0到index的截取slice,中序遍历从0到index的截取)
// head.right = 递归函数(先序遍历从index开始的截取,中序遍历从index+1开始的截取) 因为先序遍历shift了,中序遍历没shift
// return head
// *否则 return null
const buildTree = function (preorder, inorder) {
if (!preorder.length) return null;
let head = new TreeNode(preorder.shift());
// 1
let index = inorder.indexOf(head.val);
// [ 0,1 )
head.left = buildTree(preorder.slice(0, index), inorder.slice(0, index));
// [1, [2,
// preorder.slice(index) 右子树的前序遍历
// inorder.slice(index+1) 右子树的中序遍历,因为前序遍历被shift了,去掉首位3,变成
//9|20,15,7 index所以为1
//但是中序遍历没shift 为 9|3|15,20,7,所以去除右子树的中序遍历index要加1(相当于去掉父节点3)
head.right = buildTree(preorder.slice(index), inorder.slice(index + 1));
// 这⾥要注意,preorder前⾯shift⼀次⻓度⽐inorder⼩1
return head;
};
106.从中序与后序遍历序列构造二叉树
/**
* 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 {number[]} inorder
* @param {number[]} postorder
* @return {TreeNode}
*/
const buildTree = function (inorder, postorder) {
let post_idx = postorder.length - 1;
const valMapIndexofInorder = new Map();
inorder.forEach((val, idx) => {
// 用val做key,idx做val
valMapIndexofInorder.set(val, idx);
});
const helper = (l, r) => {
if (l > r) {
return null;
}
const root_val = postorder[post_idx];
const index = valMapIndexofInorder.get(root_val);
post_idx--;
const root = new TreeNode(root_val);
root.right = helper(index + 1, r);
root.left = helper(l, index - 1);
return root;
};
return helper(0, inorder.length - 1);
};
110.平衡二叉树(-114514)
给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:
一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。
var isBalanced = function (root) {
// 递归主函数
return walk(root) !== -114514;
};
const walk = function (node) {
if (!node) return 0;
// 拿到左边最大长度
const left = walk(node.left);
const right = walk(node.right);
// 已经不平衡 || 将要不平衡
if (left === -114514 || right === -114514 || Math.abs(left - right) > 1) {
return -114514;
}
return Math.max(left, right) + 1;
};
108.将有序数组转换为二叉搜索树(升序列表从中间 slice)
var sortedArrayToBST = function (nums) {
if (!nums.length) {
return null;
}
// 二叉搜索树的中序遍历,就是升序列表
// 以升序数组的中间元素作为根节点 root
const mid = Math.floor(nums.length / 2);
const root = new TreeNode(nums[mid]);
root.left = sortedArrayToBST(nums.slice(0, mid));
root.right = sortedArrayToBST(nums.slice(mid + 1));
return root;
};
110.平衡二叉树
var isBalanced = function (root) {
// 递归主函数
return walk(root) !== -999;
};
const walk = function (node) {
if (!node) return 0;
// 拿到左边最大长度
const left = walk(node.left);
const right = walk(node.right);
if (left === -999 || right === -999 || Math.abs(left - right) > 1) {
return -999;
}
return Math.max(left, right) + 1;
};
111.二叉树的最小深度
/**
* @param {TreeNode} root
* @return {number}
*/
var minDepth = function (root) {
if (root == null) {
return 0;
}
// 不像最大深度,最小深度必须分开判断,防止一条链表的情况,
// 只有两边都没有子树才是叶子节点
if (root.left == null && root.right == null) {
return 1;
}
let ans = Number.MAX_SAFE_INTEGER;
if (root.left != null) {
ans = Math.min(minDepth(root.left), ans);
}
if (root.right != null) {
ans = Math.min(minDepth(root.right), ans);
}
return ans + 1;
};
112.路径总和
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum
var hasPathSum = function (root, targetSum) {
let flag = false;
if (!root) return false;
const dfs = (curr, sum) => {
if (sum === targetSum && !curr.left && !curr.right) {
flag = true;
return;
}
if (curr.left && !flag) dfs(curr.left, sum + curr.left.val);
if (curr.right && !flag) dfs(curr.right, sum + curr.right.val);
};
dfs(root, root.val);
return flag;
};
113.路径总和 II(dfs,pushpop)
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
// 比路径总和多一个参数path,每次push path,递归下一层,再pop
// 而且比路径总和增加一个细节,
// 函数执行一开始push当前值,最后pop当前值
var pathSum = function (root, targetSum) {
if (root == null) return [];
const res = [];
function getPath(node, sum, path) {
path.push(node.val);
if (node.left == null && node.right == null && sum == targetSum) {
res.push(path.slice());
}
if (node.left) {
// 先push再pop,注意这里path不包含左值,下一次递归才会加入path
getPath(node.left, sum + node.left.val, path);
}
if (node.right) {
getPath(node.right, sum + node.right.val, path);
}
path.pop();
}
getPath(root, root.val, []);
return res;
};
114.二叉树转链表(前序遍历进数组,然后一个个拼)
给你二叉树的根结点 root ,请你将它展开为一个单链表:
展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。 展开后的单链表应该与二叉树 先序遍历 顺序相同
/**
* @param {TreeNode} root
* @return {void} Do not return anything, modify root in-place instead.
*/
var flatten = function (root) {
const list = [];
preorderTraversal(root, list);
const size = list.length;
for (let i = 1; i < size; i++) {
const prev = list[i - 1],
curr = list[i];
prev.left = null;
prev.right = curr;
}
};
const preorderTraversal = (root, list) => {
if (root != null) {
list.push(root);
preorderTraversal(root.left, list);
preorderTraversal(root.right, list);
}
};
115.不同的子序列
给你两个字符串 s 和 t ,统计并返回在 s 的 子序列 中 t 出现的个数,结果需要对 109 + 7 取模。
示例 1:
输入:s = "rabbbit", t = "rabbit" 输出:3 解释: 有 3 种可以从 s 中得到 "rabbit" 的方案。
/**
* @param {string} s
* @param {string} t
* @return {number}
*/
var numDistinct = function (s, t) {
const m = s.length,
n = t.length;
if (m < n) {
return 0;
}
const dp = new Array(m + 1).fill(0).map(() => new Array(n + 1).fill(0));
// r a t
// r 2 2 2 1
// a 0 2 2 1
// b 0 0 2 1
// b 0 0 2 1
// t 0 0 2 1
// t 0 0 1 1
// 0 0 0 1
// 右多一列下多一排,右列初始化为1
// 如果相等,则下右和,如果不等,则下,dp[0][0]
for (let i = 0; i <= m; i++) {
dp[i][n] = 1;
}
for (let i = m - 1; i >= 0; i--) {
for (let j = n - 1; j >= 0; j--) {
if (s[i] == t[j]) {
// 和下右有关
dp[i][j] = dp[i + 1][j + 1] + dp[i + 1][j];
} else {
// 和下有关
dp[i][j] = dp[i + 1][j];
}
}
}
return dp[0][0];
};
118.杨辉三角
在「杨辉三角」中,每个数是它左上方和右上方的数的和,如果左上方没有数,则用右上方
外围永远是 1
/**
* @param {number} numRows
* @return {number[][]}
*/
var generate = function (numRows) {
const ret = [];
for (let i = 0; i < numRows; i++) {
const row = new Array(i + 1).fill(1);
// 第一次遍历 1 2* 1,只循环过中间一位
// 1 3* 3* 1,只循环过中间两位
for (let j = 1; j < row.length - 1; j++) {
row[j] = ret[i - 1][j - 1] + ret[i - 1][j];
}
ret.push(row);
}
// [[1],[1,1],[1,2,1]....]
return ret;
};