算法练习笔记(四)

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
}

对称二叉树

给定一个二叉树,检查它是否是镜像对称的。

image-20211025161842757

代码

//使用递归
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

代码

来源:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solution/jian-dan-gan-jing-de-xie-fa-by-dokomzhu-25oi/

定位出根节点,划分出左右子树,然后 递归 构建左右子树

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。

进阶:

你只能使用常量级额外空间。
使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。

image-20211028122613166

思路

由题意可知,每个结点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 开始计数)。

image-20211028121944037

image-20211028122004457

思路

二叉搜索树的中序遍历是有序的,利用二叉搜索树的特点进行遍历,从左的节点开始计数,将第 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 的深度尽可能大(一个节点也可以是它自己的祖先)。”

image-20211029120830550

image-20211029121106850

来源:力扣(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
}
原文地址:https://www.cnblogs.com/Small-Windmill/p/15459197.html