【牛客算法】某司面试算法题:循环右移二叉树

一、算法题描述

1.1 算法描述

现有一棵n个节点构成的二叉树,请你将每一层的节点向右循环位移k位。某层向右位移一位(即k=1)的含义为:

  1. 若当前节点为左孩子节点,会变成当前节点的双亲节点右孩子节点

  2. 若当前节点为右儿子,会变成当前节点的双亲节点右边相邻兄弟节点左孩子节点。(如果当前节点的双亲节点已经是最右边的节点了,则会变成双亲节点同级的最左边的节点左孩子节点)

  3. 该层的每一个节点同时进行一次位移。

  4. 是从最下面的层开始位移,位移完每一层之后,再向上,直到根节点,位移完毕。

如果从最后一层开始对该二叉树的每一层循环位移k位。以下方二叉树为例,k=1:

			 1/ \2   3/ \4   5

位移最后一层,5变成2的左孩子节点,4变成3的右孩子节点,如下图:

			    1/ \2   3/     \5       4

再位移倒数第二层,3变成1的左孩子节点,2变成1的右孩子的节点,它们的孩子节点随着一起位移,如下图:

		      1/ \3   2\   /4 5

根节点没有双亲节点,不用位移,位移完毕

现在给你这棵二叉树,请你返回循环右移k位后的二叉树。

1.2 示例

1.2.1 示例1

输入

{1,2,3,#,#,4,5},1

输出

{1,3,2,#,4,5}

说明

解释见题面描述。     

1.2.1 示例2

输入

{1,2,3,4},2

输出

{1,2,3,#,#,4}

说明

      1/ \2   3/4变为1/ \2   3/4

1.2.3 示例3

输入

{1,#,3,4,5},1

输出

{1,3,#,5,4}

说明

    1\3/ \4   5变为1\3/ \5   4变为1/3/ \5   4

1.4 备注

树的节点个数在[1,10^5]之间,且保证该树上每个节点的编号不同,节点编号并非按顺序排列,1≤k≤100

1.5 提供的代码

import java.util.*;/** public class TreeNode {*   int val = 0;*   TreeNode left = null;*   TreeNode right = null;*   public TreeNode(int val) {*     this.val = val;*   }* }*/public class Solution {/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** * @param root TreeNode类 * @param k int整型 * @return TreeNode类*/public TreeNode cyclicShiftTree (TreeNode root, int k) {// write code here}
}

二、算法实现

2.1 算法思路

  1. 层序遍历:使用队列进行BFS(层次遍历),同时记录每个节点在每一层的位置信息,包括父节点位置、当前节点位置以及是否为左孩子或右孩子。将这些信息存储在levels数组中,每个元素是一个列表,包含该层所有节点的信息。

  2. 位移操作:从最底层开始,逐层向上进行位移操作。对于每一层,首先计算出这一层需要位移的步数,然后根据位移步数调整每个节点的左右子节点指针。

  3. 指针重构:在位移过程中,需要重新构建每个节点的左右子节点指针。这可以通过遍历levels数组中的每层节点,并根据它们的父节点位置和位移步数来确定新的子节点位置。

  4. 更新指针:在位移操作完成后,需要更新上一层的节点指针,将当前层的节点连接到上一层的相应节点上。

  5. 处理边界条件:在位移过程中,需要注意处理边界条件,例如当位移步数超过当前层节点数时,需要对步数进行取模操作。

2.2 算法实现

import java.util.*;/** TreeNode类定义* public class TreeNode {*   int val = 0;*   TreeNode left = null;*   TreeNode right = null;*   public TreeNode(int val) {*     this.val = val;*   }* }*/public class Solution {// Node类封装了节点的层次信息,便于后续重构指针class Node {int parentIndex;    // 父节点在当前层的位置int currentIndex;   // 当前节点在该层的索引位置int flag;           // 标记当前节点是左孩子(0)还是右孩子(1)TreeNode currentNode;  // 当前节点的引用// 构造方法public Node(int parentIndex, int currentIndex, int flag, TreeNode currentNode) {this.parentIndex = parentIndex;this.currentIndex = currentIndex;this.flag = flag;this.currentNode = currentNode;}}public TreeNode cyclicShiftTree(TreeNode root, int k) {if (root == null) return null;  // 空树处理// 存储每层的节点信息,用于后续循环位移和指针重构ArrayList<ArrayList<Node>> levels = new ArrayList<>();Queue<Node> queue = new LinkedList<>();// 初始化:根节点加入队列queue.offer(new Node(0, 0, 0, root));// `parentNum`记录当前层节点数,`nextNum`记录下一层节点数int parentNum = 1, nextNum = 0;ArrayList<Node> tempLevel = new ArrayList<>();  // 当前层的节点列表// 层次遍历:记录每层节点的结构信息while (!queue.isEmpty()) {Node node = queue.poll();tempLevel.add(node);  // 将节点加入当前层的列表--parentNum;// 添加左子节点到队列if (node.currentNode.left != null) {queue.offer(new Node(node.currentIndex, nextNum++, 0, node.currentNode.left));}// 添加右子节点到队列if (node.currentNode.right != null) {queue.offer(new Node(node.currentIndex, nextNum++, 1, node.currentNode.right));}// 当前层遍历完毕,将其加入到levels,并更新下一层if (parentNum == 0) {parentNum = nextNum;nextNum = 0;levels.add(tempLevel);tempLevel = new ArrayList<>();}}// 从树的最底层开始,逐层循环右移并更新左右子节点指针int depth = levels.size() - 1;for (int i = depth; i >= 1; --i) {  // 从最底层向上逐层处理ArrayList<Node> parentLevel = levels.get(i - 1);int parentLevelSize = parentLevel.size();// 清空上一层每个节点的左右子节点,准备重新分配指针for (Node parent : parentLevel) {parent.currentNode.left = null;parent.currentNode.right = null;}// 计算当前层的位移步数int move = k % (2 * parentLevelSize);  // 控制位移在有效范围内tempLevel = levels.get(i);// 根据位移更新每个节点的左右子节点指针for (Node node : tempLevel) {// 计算目标父节点位置和孩子标记(左孩子或右孩子)int targetParentIndex = node.flag == 0? (node.parentIndex + move / 2) % parentLevelSize: (node.parentIndex + (move + 1) / 2) % parentLevelSize;int targetChildFlag = node.flag == 0 ? move % 2 : (move + 1) % 2;// 获取目标父节点Node targetParent = parentLevel.get(targetParentIndex);// 根据targetChildFlag更新子节点指针if (targetChildFlag == 0) {targetParent.currentNode.left = node.currentNode;} else {targetParent.currentNode.right = node.currentNode;}}}return root;  // 返回根节点,树的结构已完成位移并更新}
}

2.3 算法复杂度分析

  1. 时间复杂度:算法的时间复杂度主要取决于树的节点数n以及位移步数k。在最坏情况下,我们需要对每个节点进行位移操作,因此时间复杂度为O(n * k)。然而,由于位移操作的步数k通常远小于树的节点数n,因此实际的时间复杂度通常接近O(n)。

  2. 空间复杂度:算法的空间复杂度主要取决于树的高度h和每层的节点数。在最坏情况下,我们可能需要存储所有层的节点信息,因此空间复杂度为O(n),其中n为树的节点数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/883354.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

直播系统源码技术搭建部署流程及配置步骤

系统环境要求 PHP版本&#xff1a;5.6、7.3 Mysql版本&#xff1a;5.6&#xff0c;5.7需要关闭严格模式 Nginx&#xff1a;任何版本 Redis&#xff1a;需要给所有PHP版本安装Redis扩展&#xff0c;不需要设置Redis密码 最好使用面板安装&#xff1a;宝塔面板 - 简单好用的…

Android——事件冲突处理

当我们给列表的item设置了点击事件后&#xff0c;又给item中的按钮设置了点击事件&#xff0c;此时item的点击事件会失效。 解决 给item的布局xml中设置以下属性 android:descendantFocusability"blocksDescendants"<LinearLayout xmlns:android"http://sc…

HT7181 16.8V,14A高效升压转换器

1、特征 输入电压范围:2.7V-16V 输出电压范围:最高16.8V 固定开关频率:360kHz 可编程峰值电流:14A 高转换效率: 94% (VIN 7.2V, VOUT9.3V, IOUT1.5A) 90% (VIN 7.2V, VOUT9.3V, IOUT 7A) 93% (VIN 7.2V, VOUT12V, IOUT 1.5A) 90% (VIN 7.2V, VOUT12V, IOUT 5.5A) 90% (VIN …

220V降12V1A恒流点灯WT5112

220V降12V1A恒流点灯WT5112 芯片特点 高精度恒流输出&#xff1a;WT5112 是一款适用于非隔离降压型恒流 LED 驱动芯片。在 220V 降 12V、1A 恒流点灯应用中&#xff0c;它能够提供高精度的恒流输出。其恒流精度通常可以达到 3% - 5% 左右&#xff0c;这对于 LED 灯的稳定发光非…

安卓基础001

前言 也是好久没有更新博客了,最近实习也是需要学习一些知识哈哈哈哈哈哈为了更好的发展嘛,咱们从客户端开始,过程可能有点像写前端,不喜勿喷,希望在学习的过程中也可以给大家带来一些简单得帮助吧....... tips:这里跳过安卓studio安装,大家可自行寻找教程 写的不详细,只是为了…

从“摸黑”到“透视”:AORO A23热成像防爆手机如何改变工业检测?

在工业检测领域&#xff0c;传统的检测手段常因效率低下、精度不足和潜在的安全风险而受到诟病。随着科技的不断进步&#xff0c;一种新兴的检测技术——红外热成像技术&#xff0c;正逐渐在该领域崭露头角。近期&#xff0c;小编对一款集成红外热成像技术的AORO A23防爆手机进…

君正 T31 型号芯片架构模块介绍

文章目录 1. 核心模块2. 存储模块3. 安全模块4. 图像和视频处理5. 输入输出接口6. 其他支持模块 T31 型号 MCU 结构图&#xff1a; T31 集成了高性能 CPU、多功能图像处理单元、丰富的输入输出接口以及多种安全保护机制&#xff0c;适合用于视频监控、智能家居、工业控制等高性…

改进YOLOv8系列:引入低照度图像增强网络Retinexformer | 优化低光照目标检测那题

改进YOLOv8系列:引入低照度图像增强网络Retinexformer | 优化低光照目标检测那题 🚀论文研究概括🚀加入到网络中的理论研究🚀需要修改的代码1 🍀🍀Retinexformer 代码2🍀🍀tasks里引用🚀创建yaml文件🚀测试是否创建成功前言:这篇论文提出了一种用于低光图像…

设计模式06-结构型模式1(适配器/桥接/组合模式/Java)

#1024程序员节&#xff5c;征文# 4.1 适配器模式 结构型模式&#xff08;Structural Pattern&#xff09;的主要目的就是将不同的类和对象组合在一起&#xff0c;形成更大或者更复杂的结构体。结构性模式的分类&#xff1a; ​ 类结构型模式关心类的组合&#xff0c;由多个类…

项目部署 —— 前端、后端

一、 前端 ● 二号标题 在命令框里输入 npm run build 打包成功&#xff1a; 项目就会出现一个 dist 文件夹 将Linux的nginx文件夹中&#xff0c;重命名为 news 二、 后端 ● 通过maven打包后端程序 最终会在项目中生成一个 target 文件夹&#xff0c;将 news-1.0-SNAPSHOT.…

Python爬虫,初识xpath(1)

xpath解析 抓取主页面当中所有壁纸的链接地址 xpath是专门针对xml而创建的表达式语言&#xff0c;可以直接从xml中提取表达式数据&#xff1b;也可以取html取数据&#xff1b;html是xml的子集。 1.按照lxml安装包 在python终端输入 pip install lxml from lxml import etre…

【element-tiptap】如何实现查找替换功能?

这是一个稍微复杂的功能了&#xff0c;因为 element-tiptap 中没有查找替换功能&#xff0c;需要从零开始开发。但是&#xff0c;在万能的github上有一个开源的库&#xff0c;我们可以借用一下 tiptap-search-and-replace 不过这个库是没有UI的&#xff0c;只有一个扩展的方法。…

【Linux】线程池详解及其基本架构与单例模式实现

目录 1.关于线程池的基本理论 1.1.线程池是什么&#xff1f; 1.2.线程池的应用场景&#xff1a; 2.线程池的基本架构 2.1.线程容器 2.2.任务队列 2.3.线程函数&#xff08;HandlerTask&#xff09; 2.4.线程唤醒机制 3.添加单例模式 3.1.单例模式是什么&…

【 thinkphp8 】00006 启动 内、外置服务器

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【 t…

Linux文件类型和根目录结构

Linux文件类型和根目录结构 1.文件类型 字符文件类型说明~普通文件类似于Windows的记事本d目录文件类似于windows文件夹c字符设备文件串行端口设备&#xff0c;顺序读写&#xff0c;键盘b块设备文件可供存储的接口设备&#xff0c;随机读写&#xff0c;硬盘p管道文件用于进程…

jmeter中请求参数:Parameters、Body Data的区别

使用jmeter发送请求&#xff0c;常常要伴随传递参数。有两种请求参数: Parameters, Body Data, 它们的使用方式有很大不同。 先看下get和post请求的区别。 get请求&#xff1a;顾名思义是从服务器获取资源。 post请求&#xff1a;顾名思义是往服务器提交要处理的数据。 直观…

【算法刷题指南】双指针

&#x1f308;个人主页&#xff1a; 南桥几晴秋 &#x1f308;C专栏&#xff1a; 南桥谈C &#x1f308;C语言专栏&#xff1a; C语言学习系列 &#x1f308;Linux学习专栏&#xff1a; 南桥谈Linux &#x1f308;数据结构学习专栏&#xff1a; 数据结构杂谈 &#x1f308;数据…

JavaSE要点 1】Java基础

目录 一、编译和运行 二、JDK,JRE和JVM 三、Java中的基本类型 1. 基本类型的大小 四、JVM内存模型 1. 内存模型 五、JVM虚拟机的组成 1. 虚拟机的5个组成部分 2. 虚拟机栈 3. 栈帧 六、值传递和引用传递 七、变量的默认值 八、String的不可变 九. 包装类和常量池&#xff08;-…

基于SSM的网上购物系统的设计与实现

技术介绍 本系统运用了JSP技术、SSM框架、B/S架构和myspl数据库 MySQL 介绍 MySQL是一种关系型的数据库管理系统&#xff0c;属于Oracle旗下的产品。MySQL的语言是非结构化的&#xff0c;使用的用户可以在数据上进行工作。这个数据库管理系统一经问世就受到了社会的广泛关注…

【WebGis开发 - Cesium】三维可视化项目教程---图层管理拓展图层顺序调整功能

目录 引言一、为什么要开发图层顺序调整功能二、开发思路整理1. 拖拽库方案选择2. cesium图层api查询 三、代码编写1. 编写拖拽组件代码2. 修改原有图层管理代码2.1 图层加载移除的调整2.2 图层顺序与拖拽列表的矛盾 3. 编写图层移动代码 四、总结 引言 本教程主要是围绕Cesium…