Diameter Of Tree(找到树中两个叶节点的最远距离)
题目描述:
给定一棵树的头结点,找到树中的两个节点,要求这两个节点的距离最大,返回该距离。
解题思路:
通过分析我们可以知道,一棵树的两个节点的最远距离可能来自两种情况:
- 左节点的最深深度 + 右节点的最深深度,经过根节点;
- 在左节点为根节点中的两个节点存在最远距离;在右节点为根节点中的两个节点存在最远距离;
我们用height函数找到某个节点的深度;用diameter函数找到以某个节点为根中两个叶节点的最远距离。
代码如下:
|
|
给定一棵树的头结点,找到树中的两个节点,要求这两个节点的距离最大,返回该距离。
通过分析我们可以知道,一棵树的两个节点的最远距离可能来自两种情况:
我们用height函数找到某个节点的深度;用diameter函数找到以某个节点为根中两个叶节点的最远距离。
|
|
给定一棵树的头结点和一个目标值;判断是否树中存在一条从根到叶的路径,其路径上节点和的值为目标值。
这题是leetcode上的题目,可以看这上面的题目描述.
主要的思路还是递归来解决这道题目。我们在不断的遍历树的过程中,对sum值进行改变,即减去当前遍历节点上的值;如果遇到了当前是叶节点,并且其值和当前的目标值相同,就直接返回true.
|
|
给定一棵树的头结点和一个目标值;找到树中所有从根到叶节点和为目标值的情况并返回。
leetcode上的题目描述
本题的思路在与使用回溯的方法;但是需要注意的点是什么时候回溯。我们用一个vector保存当前路径的节点;用一个vector保存每次符合条件后保存路径。
|
|
给定一棵树的头节点和一个目标值,要求返回树中任意从父节点到子节点路径和为目标值的个数。
这题也是leetcode上的题目,详情可见此处.
当然这题的思路依旧是递归的方式;但是有不同的是,我们需要判断在遍历到当前节点的时候,其遍历的路径上的子路径是否存在符合条件的情况。所以我们主要是用一个vector保存了遍历到当前节点的路径上的累加和;这样我们就可以通过遍历累加和数组来判断当前路径上是否存在符合要求的路径。
|
|
给定一棵树的头结点,从树的头结点到根节点的每一条路径都代表了一个数,要求返回所有路径代表的数的和。
这道题的具体描述可以看LeetCode129.
主要解题思路也是很直接,我们不断的往树的深度遍历,主要用一个变量来记录每条路径上所代表的数,用一个变量记录所有路径的总和即可。
|
|
给定一棵树的头结点,要求返回树中的每一条路径表示,例如1->2->3等。
依旧是LeetCode的题目LeetCode257。具体描述可以看这里。解题思路不再赘述。
|
|
给定一棵树的头结点,要求返回树的每条路径上各自的最大值。
具体题目描述可以看LeetCode515.
这边代码的解法使用的是按层遍历的方式,找到每一条路径上的数然后保存排序找到最大值;当然也可以直接遍历。
|
|
给定一个长度为n的数组;要求找到3个切分点i,j,k满足如下要求:
输入时[1,2,1,2,1,2,1]的符合题意的切分点是[1,3,5],见[LeetCode548]
首先为了计算切分的段落和,我们可以构建一个累加和数组,其中sum[i]代表数组[0,i]的数据和,这样可以计算任意段落的和了;然后我们可以遍历i,j,k不同的位置用来判断是否满足条件即可。需要注意的点有因为数组中可以有负数,所以不能根据累加和肯定递增,如果当前位置不满足条件后面肯定不满足这个想法来剪枝;另外测试用例中包含了大量的0;对于计算累加和的时间消耗太多;所以需要针对这个情况做累加和计算的改进。
|
|
这题来源于LeetCode,具体可以看这里.
第一种解题思路是找到打印的规律;主要有两个地方:
|
|
第二种解题思路我们可以将每行存入数组,我们遍历字符串,利用标记变量决定存入数组的方式,存入的方式根据锯齿的走向决定向上还是向下;向上走到第0行后就向下;向下走到nrows - 1后就向上走。
class Solution {
public:
string convert(string s, int numRows) {
if (numRows == 1) return s;
string res[numRows];
string result;
int step = 0;
int row = 0;
for (int i = 0; i < s.size(); i++){
res[row] = res[row] + s[i];//存入数组
if (row == 0) step = 1;
if (row == numRows - 1) step = -1; //决定走向
row = row + step;//数组下标随走向决定
}
for (int i = 0; i < numRows; i++){
result = result + res[i];//将数组连起来返回
}
return result;
}
};
给定两个字符串,找到两个字符串的最长非公共子序列。其中子序列的定义为:原序列中删除部分字符所得到,即原始序列中的字符顺序不改变。即假设字符串str1和str2。找到str1中的最长子序列,且该序列无法由str2得到。另外我们设定str1和””都是str1的子序列。如果”aa”和”aa”的话,不存在非公共子序列,返回-1.
“abc”和”cdc”的最长子序列是”abc”(“cdc”)。所以最长的非公共子序列长度为3.见LeetCode521
初看题目会陷入困局;想要找到”abc”中的所有子序列然后和”cdc”一一验证。但是其实我们从另外一个角度看,我们可以先将两个字符串相同的情况排除后;在两个字符串不同长度的情况下,肯定是较长的字符串的本身是我们需要的结果。因为较长的字符串肯定无法通过另外一个串得到,所以较长的串就是我们所求的。
|
|
给定一个字符串数组,找到字符串数组中的最长非公共子序列。
“abc”, “cde”, “fgh”的最长公共子序列的长度是3,任意的一个字符串都是最长非公共子序列。
与上一题类似,我们想直接利用最长的那个字符来作为结果返回;但是”aaa”,”aaa”,”bb”这样的情况导致结果不符合题意;所以需要利用哈希表来过滤掉超过两次的字符串;但是仅仅这样还是不够;因为如果输入是”aaa”,”aaa”,”aa”这样的情况下是不存在所谓的非公共子序列。所以思路是我们找到一个字符串,判断它是否是最长公共子序列的方法是与比它长的字符串比较,只有它不是所有比它长的字符串的子序列才可以成为最长子序列。
|
|
给定一个树的头结点,判断这棵树是不平衡二叉树。平衡二叉树的定义是左右对当前节点而言,左子树和右子树的深度差值不超过1;且左右子树也是平衡二叉树。
对于树的问题大部分都是采用递归的方式进行求解的,这一题也是。不过在判断是否是平衡儿叉树的过程需要记录当前节点的深度用来判断左右节点高度的差值;另外利用一个state变量来保存当前遍历过程中得到树的状态,如果已经知道是非平衡二叉树直接返回即可。
|
|
给定一棵树的头节点,要求判断这棵树是不是二叉搜索树。
具体的题目描述可以看LeetCode98.
因为是搜索二叉树,所以我们可以通过中序遍历的结果看其是否是升序的来判断是否是搜索二叉树。自然还有递归的解法待下次补上。
|
|
给定两棵树,要求判断这两棵树是否相等。
具体描述可以看LeetCode100.
|
|
给定两棵树的头节点,要求判断这两棵树是否是互为镜像。
具体描述可以看LeetCode101.
|
|
给定两棵树的根节点T1,T2;判断T1中是否包含了T2的全部拓扑结构。
主要的想法还是递归解决这个问题。首先我们在寻找两棵树是否相等过程中使用先序遍历的方法。我们可以先判断当前节点的相等关系,如果相等,则递归的判断左节点和右节点;如果不等我们可以判断当前节点的左子树和右子树和目标节点的包含关系。
|
|
给定一棵树的头结点head,实现按层遍历打印。
按层遍历的思路通常是借助于队列数据结构。我们先将节点入队,出队的时候将该节点的左右节点各自入队,当上一层的节点出队结束后,我们继续将刚刚入队的这一层节点出队,实现了按层遍历。我们可以使用两个队列分别来记录上一层和当前层的节点;也可以只用一个队的方法,每次记录当前入队的最后一个节点,下一层遍历的时候我们就只要出队到该节点即可。
|
|
|
|
自底向上按层遍历树的每一层节点并返回结果。与上面题目类似,具体的题目描述可以看LeetCode107.
|
|
定义树中的节点增加一个next节点,要求给定一棵树的头结点,要求每层的树的节点的next指针指向其同层右侧的指针。
初看题目可能会觉得思路上会有点卡壳,但是如果之前做过树的按层遍历的话,应该不难想到,我们可以一层一层的遍历树的节点,然后将每一层的树的节点连接起来就可以。
|
|
类似用到树的按层遍历的性质的有,给定一棵树的头结点,要求输出从右侧看这棵树,从第一层到最后一层所看见的树的节点。其实这题的主要思路也是类似的,因为我们知道每层的节点后,我们只要将当前层的末尾节点保存到结果中就可以了。所以需要举一反三,利用之前的题目的解法可以很快的解答出。
这题也是leetcode上的题目,具体的题目描述可以看这边.
|
|
给定一棵树的头结点,要求返回树的最左侧下方的那个节点。具体的描述可以看LeetCode513.解题思路是按层遍历,找到最后一层的最左侧节点返回即可。
|
|
给定一棵树的头结点,要求我们按照Z字型分层打印树的内容。
同样我们可以利用按层遍历树的方式,不同之处是需要加上一个direction标识用于判断当前层是从前往后还是从后往前答应。具体的题目描述可以看LeetCode103。
|
|
二叉树被记录文件的过程称为二叉树的序列化。通过文件来重建二叉树的过程称为二叉树的反序列化。给定一棵树的头结点head,设计一种二叉树序列化和反序列化的方案。
我们用!放在遍历结果的后面表示当前节点的结束,用#!表示当前节点为空结束。这样通过先序遍历一棵树得到的结果为:12!3!#!#!#!.
所以我们可以利用树的先序遍历来得到一棵树的序列化结果。在遍历每个节点后加上!,在每个根节点后面加上#!.
|
|
对于树我们也可以使用按层遍历的方法得到其序列化的结果。使用的规则和上诉的一致,我们在节点结束后加上!,在空节点上加上#!.
|
|
对于反序列化而言,我们首先要将拿到的字符串根据!隔开,分隔出每个节点的数值。因为原始数据是根据先序遍历得到的,所以假设在分隔后得到的字符串数组是[“12”,”3”,”#”,”#”,”#”].我们首先取出第一个字符串,开辟空间新建节点,用剩下的数据作为其左子树;取出第二个节点3生成节点,用剩下的作为左子树,发现是空节点,所以用剩下的构建右子树依旧是空节点;所以用[“#”,”#”]构建12节点的右子树。
|
|
给定一棵树的头结点;给出先序遍历、中序遍历和后序遍历树的结果。
先序遍历是先遍历根节点,然后左节点,最后右节点;中序遍历是先遍历左节点,然后根节点最后右节点;后序遍历是最后遍历根节点。先序中序后序是以根节点为标准。
树的遍历主要是利用递归的方式进行查找。
|
|
当然我们也可以使用非递归的方式对树进行遍历;主要的思路是在于将节点入栈后,根据不同的将左节点和右节点的压栈方式能够得到不同的遍历结果。
对于先根遍历而言,我们将某节点出栈后,先将该节点的右节点入栈,然后左节点入栈;对于中序遍历而言,我们是不断将最左侧的节点入栈,然后在弹出某节点后,将该节点的右侧节点入栈即可实现中序遍历;对于后序遍历而言我们利用了2个栈的方式,首先将根节点放入栈1,每次弹出的节点都放入栈2,并且将弹出节点的左侧和右侧节点压入栈1;不断进行直到栈1为空即可。
|
|