算法练习笔记(四)
10.25
①字符串中的第一个唯一字符
给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。
示例:
s = "leetcode"
返回 0
s = "loveleetcode"
返回 2
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/first-unique-character-in-a-string
思路
:
①使用数组两次遍历,第一次统计每个字符出现的次数,第二次找到次数仅为1的字符,返回其索引
②使用s.indexOf(s[i])===s.lastIndexOf(s[i]) 找到首次出现和最后一次出现的索引相同的字符,即为不重复的字符
代码
:
//第一种
var firstUniqChar = function(s){
// 长度为26的数组,存放字符的出现次数
const arr = new Array(26).fill(0)
//统计字符出现的次数
for(let i=0;i<s.length;i++){
arr[s[i].charCodeAt(0)-97]++
}
//再次遍历,找到唯一字符
for(let i=0;i<s.length;i++){
if(arr[s[i].charCodeAt(0)-97]===1){
return i
}
}
return -1
}
//第二种
var firstUniqChar = function(s){
for(let i=0;i<s.length;i++){
if(s.indexOf(s[i])===s.lastIndexOf(s[i])){
return i
}
}
return -1
}
②对称二叉树
给定一个二叉树,检查它是否是镜像对称的。
代码
//使用递归
const isMirror = function(left,right){
//左子树右子树都为空
if(!left&&!right){
return true
}
//只有一边为空
if(!left||!right){
return false
}
//递归比较左子树和右子树
if(left.val === right.val){
return isMirror(left.left,right.right)&&isMirror(left.right,right.left)
}
return false
}
var isSymmetric = function(root){
return isMirror(root.left,root.right)
}
10.26
① 二叉树的最大深度
给定一个二叉树,找出其最大深度。
二叉树的深度为根节点到最远叶子节点的最长路径上的节点数。
说明: 叶子节点是指没有子节点的节点。
示例:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回它的最大深度 3 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree
思路
:
①递归:一个树的最大深度 = 根节点的高度(即1)+ 左右子树的最大深度中的较大者。
②BFS
代码
:
//递归
var maxDepth = function(root){
if(!root) return 0
//计算左子树的深度
let left = maxDepth(root.left)
//计算右子树的深度
let right = maxDepth(root.right)
return Math.max(left,right)+1
}
//BFS
var maxDepth = function(root){
if(!root) return 0
const queue = []
queue.push(root)
let maxDepth = 1
while(queue.length){
//记录当前层的节点个数
let len = queue.length
//逐个让当前层的节点出列
for(let i=0;i<len;i++){
const cur = queue.shift()
//左右子节点入列
if(cur.left) queue.push(cur.left)
if(cur.right) queue.push(cur.right)
}
// 当前层所有节点已经出列,如果队列不为空,说明有下一层节点,maxDepth+1
if(queue.length) maxDepth++
}
return maxDepth
}
② 二叉树的层序遍历
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
示例:
二叉树:[3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其层序遍历结果:
[
[3],
[9,20],
[15,7]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal
代码
:
var levelOrder = function(root) {
//初始化结果数组
const res = []
//处理边界条件
if(!root) return res
const queue = []
queue.push(root)
//队列不为空时,反复执行以下逻辑
while(queue.length){
//记录当前层的节点个数
let len = queue.length
//cur存储当前层的节点
let cur = []
for(let i=0;i<len;i++){
//取出队列的头部元素
const top = queue.shift()
//将头部元素的值推入cur数组
cur.push(top.val)
//如果当前结点有左右孩子,则推入下一层级
if(top.left) queue.push(top.left)
if(top.right) queue.push(top.right)
}
//将cur推入结果数组
res.push(cur)
}
//返回结果数组
return res
};
10.27
①二叉树的锯齿形层序遍历
给定一个二叉树,返回其节点值的锯齿形层序遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
例如:
给定二叉树 [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回锯齿形层序遍历如下:
[
[3],
[20,9],
[15,7]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-zigzag-level-order-traversal
思路
:在层序遍历的基础上,设置标志判断奇数层和偶数层的添加方法
代码
:
//BFS
var zigzagLevelOrder = function(root){
//结果数组
const res = []
if(!root)return res
const queue = []
queue.push(root)
//初始化标志
let isRightOrder = false
while(queue.length){
const len = queue.length
//保存该层节点
const cur = []
for(let i=0;i<len;i++){
let top = queue.shift()
if(isRightOrder){
cur.unshift(top.val)
}else{
cur.push(top.val)
}
//记录该节点的左右节点
if(top.left){
queue.push(top.left)
}
if(top.right){
queue.push(top.right)
}
}
res.push(cur)
isRightOrder = !isRightOrder
}
return res
}
//递归DFS
var zigzagLevelOrder = function(root){
const arr = []
function loop(node,level){
if(!node)return
if(!arr[level])arr[level] = []
if(level%2){//实现从右往左
arr[level].unshift(node.val)
}else{//实现从左往右
arr[level].push(node.val)
}
//进入下一层
loop(node.left,level+1)
loop(node.right,level+1)
}
loop(root,0)
return arr
}
②从前序与中序遍历序列构造二叉树
给定一棵树的前序遍历 preorder 与中序遍历 inorder。请构造二叉树并返回其根节点。
示例 1:
Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]
示例 2:
Input: preorder = [-1], inorder = [-1]
Output: [-1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal
代码
:
定位出根节点,划分出左右子树,然后 递归 构建左右子树
var buildTree = function(preorder,inorder){
if(!preorder.length||!inorder.length) return null
let node = new ListNode(preorder[0])
let index = inorder.indexOf(preorder.shift())
node.left = buildTree(preorder,inorder.slice(0,index))
node.right = buildTree(preorder,inorder.slice(index+1))
return nodex
}
10.28
①填充每个节点的下一个右侧节点指针
给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
进阶:
你只能使用常量级额外空间。
使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
思路
:
由题意可知,每个结点root
,它的左孩子root.left
的next指向右孩子root.right
(有左孩子肯定有右孩子),而它的右孩子root.right
指向父节点root
的邻居左孩子,即root.nextl.left(只要root.next
存在)。
代码
:
var connect = function(root){
if(!root)return null
//存在左孩子
if(root.left){
root.left.next = root.right
//存在邻居
if(root.next){
root.right.next = root.next.left
}
}
connect(root.left)
connect(root.right)
return root
}
②二叉搜索树中第K小的元素
给定一个二叉搜索树的根节点 root
,和一个整数 k
,请你设计一个算法查找其中第 k
个最小元素(从 1 开始计数)。
思路
:
二叉搜索树的中序遍历是有序的,利用二叉搜索树的特点进行遍历,从左的节点开始计数,将第 k 个节点的值返回。
代码
:
var kthSmallest = function(root, k) {
let ans
function inorderTraverse(root){
if(!root||k<0)return null
inorderTraverse(root.left)
if(--k == 0){
ans = root.val
}
inorderTraverse(root.right)
}
inorderTraverse(root)
return ans
}
10.29
①二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree
思路
:
参考https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/solution/jsersi-lu-hao-li-jie-by-hyj8/
代码
:
var lowestCommonAncestor = function(root,p,q){
if(!root||p==root||q==root)return root
const left = lowestCommonAncestor(root.left,p,q)
const right = lowestCommonAncestor(root.right,p,q)
if(left&&right){
return root
}
if(!left){
return right
}
return left
}
②3的幂
给定一个整数,写一个函数来判断它是否是 3 的幂次方。如果是,返回 true ;否则,返回 false 。
整数 n 是 3 的幂次方需满足:存在整数 x 使得 n == 3x
示例 1:
输入:n = 27
输出:true
示例 2:
输入:n = 0
输出:false
示例 3:
输入:n = 9
输出:true
示例 4:
输入:n = 45
输出:false
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/power-of-three
代码
:
//递归
var isPowerOfThree = function(n){
if(n == 1)return true
if(n == 0||n%3!==0)return false
return isPowerOfThree(n/3)
}
//循环
var isPowerOfThree = function(n){
while(n>1){
n /= 3
}
return n==1
}