获得徽章 0
- leetcode 111 二叉树的最小深度-层序遍历法:
使用层序遍历,先记录深度,在遍历每一层节点的时候,判断节点的左右节点是否存在,如果都不存在,则返回此时的深度即可评论点赞 - leetcode 100 二叉树的右视图
我们可以改变一下层序遍历的顺序,以前的层序遍历是从左往右,而我们从右往左,这样每一层第一个入队列的就是最右边的元素。此时我们只将这个元素的值存入即可。(此方法需要定义一个变量来记录第一个)
此外我们也可以直接用原先层序遍历的方法,通过每层遍历是否为最后一个元素来确实是否是最右边的元素,直接保存将其值也可。展开评论点赞 - leetcode 199.二叉树的右视图
我们也可以直接用层序遍历的方法,通过size === 1 来判断最右边的元素,直接保存将其值即可。
此外,我们也可以改变一下层序遍历,以前的层序遍历是从左往右,而我们从右往左,这样每一层第一个入队列的就是最右边的元素。此时我们只将这个元素的值存入即可。(此方法可能需要定义一个变量来记录第一个)展开评论点赞 - leetcode 102:层序遍历
层序遍历类似于图的广度优先搜索,我们使用队列来存放遍历的节点,同时定义一个size来记录每一层的节点的数量。(因为我们一开始是将一层的节点都入队列,因此在这个时候需要记录一下此时队列的长度,也就是这一层节点是数量。以此来控制我们出队列的元素的数量。)
因此,内循环要通过size来控制,不能通过队列的长度控制,因为我们上一层的某个节点在出队列的同时,其左右子节点会入队列。通过size来控制队列弹出的元素个数,这样每一层内循环结束后,队列内的节点都为同在一层的节点。所以我们这个时候获取队列的长度,那么也就是这一层节点的数量size。代码如下:
function levelOrder(root: TreeNode | null): number[][] {
const res: number[][] = [];
if(root === null) {
return res;
}
const queue: TreeNode[] = [];
let curNode: TreeNode | null = null;
queue.push(root);
while(queue.length > 0){
let size = queue.length;
let arry: number[] = [];
while(size > 0){
curNode = queue.shift();
arry.push(curNode.val);
size--;
if(curNode.left !== null){
queue.push(curNode.left);
}
if(curNode.right !== null){
queue.push(curNode.right);
}
}
res.push(arry);
}
return res;
}展开评论点赞 - 二叉树的统一迭代遍历方法。
由于我们之前的迭代遍历方法,先序访问的节点就是我们要处理的节点,而中序不是,所以其思想不同,而我们要弄一个都适用的方法,因此那我们就将访问的节点放入栈中,把要处理的节点也放入栈中但是要做标记。
如何标记呢,就是要处理的节点放入栈之后,紧接着放入一个空指针作为标记。
我们将访问的节点直接加入到栈中,但如果是处理的节点则后面放入一个空节点, 这样只有空节点弹出的时候,才将下一个节点放进结果集。展开评论点赞 - 被leetcode吊打第十四天:二叉树前序的非递归前后遍历
前序的非递归
使用栈的结构来处理。由于栈是后进先出的。因此对于前序遍历(中左右的情况),我们放入栈的时候,应该是根节点先加入栈,然后弹出。对于其左右的子节点,应该为先将右节点放入,再放入左节点。
所以我们只需要定义一个栈、一个存放节点值的数组即可。
后序的非递归:
与前序类似,我们的前序是将中左右的值存入数组,对于子节点的操作,我们是先放入右节点,后放入左节点这样栈内就是先为右子树,后为左子树
那么后序,我们将前序的节点值的数组反转一下,就是右左中的值,离我们的左右中的顺序就是子树进栈的顺序不同。因此将前序的左子节点入栈和右子节点入栈顺序换一下即可。展开评论点赞 - 二叉树的先、中、后序遍历的迭代实现
我们在迭代前,需要知道我们迭代结束的条件是什么:
当前节点为空的时候,return。
而我们的root指向的是某个具体的节点。拿后序来说,也就是到某个节点的左/右节点为空的时候,递归才会回退一步,指向后面的将这个节点的值push进数组
var postorderTraversal = function(root) {
const roots = [];
const dfs = function(root){
if(root === null){
return;
}
dfs(root.left);
dfs(root.right);
roots.push(root.val);
}
dfs(root)
return roots;
};展开评论点赞 - 被leetcode吊打第十二天:四数之和
该题与三数之和类似,
四数之和的双指针解法是两层for循环nums[a] + nums[b]为确定值,依然是循环内有left和right下标作为双指针,找出nums[a] + nums[b] + nums[left] + nums[right] == target的情况
但是有一些细节需要注意,例如: 不要判断nums[k] > target 就返回了,三数之和 可以通过 nums[i] > 0 就返回了,因为 0 已经是确定的数了,四数之和这道题目 target是任意值。组是[-4, -3, -2, -1],target是-10,不能因为-4 > -10而跳过
此外,内层循环的break和return的使用也需要注意,不能用return,而是用break展开评论点赞 - 被leetcode吊打第十一天:三数之和,梦破碎的地方。
最开始想的是类似于两数之和的方法,算num1+num2的和,再对其和num2用map,但是去重太麻烦了,之间报错。后续看了题解发现需要使用双指针的方式
首先将数组排序,然后有一层for循环,i从下标0的地方开始,同时定一个下标left 定义在i+1的位置上,定义下标right 在数组结尾的位置上。
我们的思想就是先定一个i,然后找left和right,然后再找这个i对应的所有的
移动left 和right:
如果nums[i] + nums[left] + nums[right] > 0 就说明 此时三数之和大了,因为数组是排序后了,所以right下标就应该向左移动,这样才能让三数之和小一些。
如果 nums[i] + nums[left] + nums[right] < 0 说明 此时 三数之和小了,left 就向右移动,才能让三数之和大一些,直到left与right相遇为止。
对于去重我们可以理解为固定两个后,对第三个进行去重。
i 的 去重:判断i左侧的(也就是在三元组里出现过的),如果遇到一样,那也就是说这个值对于i已经用过了,直接换成下一个值。
left和right的去重:是为了防止我们找到了一个三元组后,(此时固定了 i 和 left/right),后续三元组的right/left 值和之前的一样。因此对于left需要循环判断left与left右侧的元素是否相等,对于right需要判断right与right左侧的元素是否相等展开评论点赞 - 被leetcode吊打第十一天,239. 滑动窗口最大值
该题我们可以使用单调队列,即单调递减或单调递增的队列。与优先级队列不同处在于:如何维护元素里的单调增和单调减(也就是说这个队列其实是我们diy出来的)
针对不同的题目单调队列的处理也不同。
在该题中,我们的单调队列(单调减的)只需要维护可能成为最大值的元素(不需要维护整个窗口)。也就是让出口处始终为滑动窗口当前的最大值元素。
pop(value):如果窗口移除的元素value等于单调队列的出口元素(也就是此时窗口的最大值),那么队列弹出元素,否则不用任何操作(因为其他元素已经在push的时候被我们移出队列了)
push(value):如果push的元素value大于入口元素的数值,那么就将队列入口的元素弹出,直到push元素的数值小于等于队列入口元素的数值为止
而我们要push、shift的value,就是滑动窗口移动的过程中,nums应该加入、移出滑动窗口的元素。展开评论点赞