算法训练营day18

2024-04-21 00:04
文章标签 算法 训练营 day18

本文主要是介绍算法训练营day18,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

        • 一、找树左下角的值
        • 二、路径总和1 & 2
          • 从路径总和1 & 2体会什么情况下递归需要返回值,什么时候不需要返回值
          • 路径总和1
          • 初始递归
          • DFS
          • BFS
          • 路径总和2
        • 三、从中序与后序遍历序列构造二叉树
        • 四、从前序和中序遍历序列构造二叉树

一、找树左下角的值

参考链接513. 找树左下角的值 - 力扣(LeetCode)

二叉树的最深最左侧的节点的值,涉及到最深 -> 联想到 层序遍历

BFS

class Solution {public int findBottomLeftValue(TreeNode root) {Deque<TreeNode> d = new ArrayDeque<>();d.addLast(root);int ans = 0;while (!d.isEmpty()) {int sz = d.size();ans = d.peek().val;while (sz-- > 0) {TreeNode poll = d.pollFirst();if (poll.left != null) d.addLast(poll.left);if (poll.right != null) d.addLast(poll.right);}}return ans;}
}

DFS

class Solution {int max, ans;public int findBottomLeftValue(TreeNode root) {dfs(root, 1);return ans;}void dfs(TreeNode root, int depth) {if (root == null) return ;if (depth > max) {max = depth; ans = root.val;}//左侧先执行dfs方法,如果最后一行存在多个节点,那么左侧的节点必定先执行//那么当执行到右侧的时候由于 depth == max,最先记录的永远是最左边的节点dfs(root.left, depth + 1);dfs(root.right, depth + 1);}
}
二、路径总和1 & 2
从路径总和1 & 2体会什么情况下递归需要返回值,什么时候不需要返回值
路径总和1
初始递归
   class Solution {public boolean hasPathSum(TreeNode root, int sum) {// 如果根节点为空,直接返回falseif (root == null) return false;// 如果当前节点是叶子节点(即左右子节点都为空),检查路径和是否等于目标值if (root.left == null && root.right == null) {return sum == root.val;}// 如果当前节点不是叶子节点,递归地在左子树和右子树中查找路径// 路径和等于目标值减去当前节点的值return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum - root.val);
}
DFS
  class Solution {
public boolean hasPathSum(TreeNode root, int sum) {// 如果根节点为空,直接返回falseif (root == null) return false;// 调用深度优先搜索(DFS)函数,查找是否存在一条从根节点到叶子节点的路径,使得路径上的节点值之和等于给定的目标值return dfs(root, sum, root.val);
}private boolean dfs(TreeNode root, int target, int pathSum) {// 如果当前节点为空,直接返回falseif (root == null) return false;// 如果路径和等于目标值,并且当前节点是叶子节点(即左右子节点都为空),返回trueif (pathSum == target && root.left == null && root.right == null) {return true;}// 初始化左右子树的标志位为falseboolean leftFlag = false, rightFlag = false;// 如果左子节点不为空,递归地在左子树中查找路径,路径和等于当前路径和加上左子节点的值if (root.left != null) {leftFlag = dfs(root.left, target, pathSum + root.left.val);}// 如果右子节点不为空,递归地在右子树中查找路径,路径和等于当前路径和加上右子节点的值if (root.right != null) {rightFlag = dfs(root.right, target, pathSum + root.right.val);}// 如果左子树或右子树中存在满足条件的路径,返回true,否则返回falsereturn leftFlag || rightFlag;
}
BFS
  class Solution {
public boolean hasPathSum(TreeNode root, int sum) {// 如果根节点为空,直接返回falseif (root == null) return false;// 创建一个队列,用于广度优先搜索(BFS)Deque<Pair<TreeNode, Integer>> queue = new LinkedList<>();// 将根节点和它的值作为一个对(Pair)添加到队列中queue.offer(new Pair<>(root, root.val));// 当队列不为空时,继续循环while (!queue.isEmpty()) {// 从队列中取出一个对Pair<TreeNode, Integer> pair = queue.poll();// 获取对中的节点和路径和TreeNode node = pair.getKey();int pathSum = pair.getValue();// 如果当前节点是叶子节点(即左右子节点都为空),并且路径和等于目标值,返回trueif (node.left == null && node.right == null && pathSum == sum) {return true;}// 如果左子节点不为空,将左子节点和当前路径和加上左子节点的值作为一个对添加到队列中if (node.left != null) {queue.offer(new Pair<>(node.left, pathSum + node.left.val));}// 如果右子节点不为空,将右子节点和当前路径和加上右子节点的值作为一个对添加到队列中if (node.right != null) {queue.offer(new Pair<>(node.right, pathSum + node.right.val));}}// 如果遍历完所有节点都没有找到满足条件的路径,返回falsereturn false;
}
路径总和2

参考链接113. 路径总和 II - 力扣(LeetCode)

先序遍历 + 路径记录

class Solution {LinkedList<List<Integer>> res = new LinkedList<>();LinkedList<Integer> path = new LinkedList<>();public List<List<Integer>> pathSum(TreeNode root, int targetSum) {recur(root, targetSum);return res;}void recur(TreeNode root, int tar) {if (root == null) return;path.add(root.val);tar -= root.val;if (tar == 0 && root.left == null && root.right == null)res.add(new LinkedList<Integer>(path));recur(root.left, tar);recur(root.right, tar);path.removeLast();}
}
三、从中序与后序遍历序列构造二叉树
class Solution {Map<Integer, Integer> map;  // 方便根据数值查找位置public TreeNode buildTree(int[] inorder, int[] postorder) {map = new HashMap<>();for (int i = 0; i < inorder.length; i++) { // 用map保存中序序列的数值对应位置map.put(inorder[i], i);}return findNode(inorder,  0, inorder.length, postorder,0, postorder.length);  // 前闭后开}public TreeNode findNode(int[] inorder, int inBegin, int inEnd, int[] postorder, int postBegin, int postEnd) {// 参数里的范围都是前闭后开if (inBegin >= inEnd || postBegin >= postEnd) {  // 不满足左闭右开,说明没有元素,返回空树return null;}int rootIndex = map.get(postorder[postEnd - 1]);  // 找到后序遍历的最后一个元素在中序遍历中的位置TreeNode root = new TreeNode(inorder[rootIndex]);  // 构造结点int lenOfLeft = rootIndex - inBegin;  // 保存中序左子树个数,用来确定后序数列的个数root.left = findNode(inorder, inBegin, rootIndex,postorder, postBegin, postBegin + lenOfLeft);root.right = findNode(inorder, rootIndex + 1, inEnd,postorder, postBegin + lenOfLeft, postEnd - 1);return root;}
}
四、从前序和中序遍历序列构造二叉树

注,本文方法只适用于“无重复节点值”的二叉树。

为了提升效率,本文使用哈希表 dic 存储中序遍历的值与索引的映射,查找操作的时间复杂度为 O(1) 。

class Solution {int[] preorder;HashMap<Integer, Integer> dic = new HashMap<>();public TreeNode buildTree(int[] preorder, int[] inorder) {this.preorder = preorder;for(int i = 0; i < inorder.length; i++)dic.put(inorder[i], i);return recur(0, 0, inorder.length - 1);}TreeNode recur(int root, int left, int right) {if (left > right) return null;                          // 递归终止TreeNode node = new TreeNode(preorder[root]);          // 建立根节点int i = dic.get(preorder[root]);                       // 划分根节点、左子树、右子树node.left = recur(root + 1, left, i - 1);              // 开启左子树递归node.right = recur(root + i - left + 1, i + 1, right); // 开启右子树递归return node;                                           // 回溯返回根节点}
}

这篇关于算法训练营day18的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/921679

相关文章

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

poj 3974 and hdu 3068 最长回文串的O(n)解法(Manacher算法)

求一段字符串中的最长回文串。 因为数据量比较大,用原来的O(n^2)会爆。 小白上的O(n^2)解法代码:TLE啦~ #include<stdio.h>#include<string.h>const int Maxn = 1000000;char s[Maxn];int main(){char e[] = {"END"};while(scanf("%s", s) != EO

秋招最新大模型算法面试,熬夜都要肝完它

💥大家在面试大模型LLM这个板块的时候,不知道面试完会不会复盘、总结,做笔记的习惯,这份大模型算法岗面试八股笔记也帮助不少人拿到过offer ✨对于面试大模型算法工程师会有一定的帮助,都附有完整答案,熬夜也要看完,祝大家一臂之力 这份《大模型算法工程师面试题》已经上传CSDN,还有完整版的大模型 AI 学习资料,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

dp算法练习题【8】

不同二叉搜索树 96. 不同的二叉搜索树 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。 示例 1: 输入:n = 3输出:5 示例 2: 输入:n = 1输出:1 class Solution {public int numTrees(int n) {int[] dp = new int

Codeforces Round #240 (Div. 2) E分治算法探究1

Codeforces Round #240 (Div. 2) E  http://codeforces.com/contest/415/problem/E 2^n个数,每次操作将其分成2^q份,对于每一份内部的数进行翻转(逆序),每次操作完后输出操作后新序列的逆序对数。 图一:  划分子问题。 图二: 分而治之,=>  合并 。 图三: 回溯:

最大公因数:欧几里得算法

简述         求两个数字 m和n 的最大公因数,假设r是m%n的余数,只要n不等于0,就一直执行 m=n,n=r 举例 以18和12为例 m n r18 % 12 = 612 % 6 = 06 0所以最大公因数为:6 代码实现 #include<iostream>using namespace std;/