在做题之前说明
offer()
方法与offerLast()
Deque
接口中的offer()
方法与offerLast()
方法都用于向双端队列的末尾添加元素,但它们之间有细微的差别。
offer()
方法是Queue
接口中定义的 ,它被所有实现了Queue
接口的类继承,包括Deque
。当你调用offer()
方法时,它会将元素添加到Deque
的末尾。如果Deque
已经满了 ,offer()
方法将抛出一个IllegalStateException
。而offerLast()
方法是**Deque
接口特有的,** 在Deque
已满时不会抛出异常 ,而是返回一个特殊的值false
,表明元素没有被添加到队列中。这种行为使得offerLast()
方法在某些情况下更加健壮,因为它避免了因队列满而导致的程序异常。
peek()
和peekFirst()
peek()
方法是从**Queue
接口继承来的** ,它返回队列头部的元素,但不移除它。如果队列为空,则peek()
方法返回null
。
peekFirst()
方法是**Deque
接口特有的** ,它与peek()
方法类似,也是返回队列头部的元素,但不移除它。然而,与peek()
方法不同的是,peekFirst()
方法不会抛出空指针异常 ,即使队列为空。当队列为空时,peekFirst()
方法返回null
。这使得peekFirst()
方法在某些情况下更加安全和可靠。
以此类推,其他的比如poll()和pollFirst()也是如此;
算法题
Leetcode 102.二叉树的层序遍历
题目链接:102.二叉树的层序遍历
大佬视频讲解:二叉树的层序遍历视频讲解
个人思路
层序遍历也就是图论中的广度优先遍历,是使用队列的结构;用队列一层层遍历,并加入结果数组,最后返回;
解法
迭代法
java
class Solution {
public List<List<Integer>> resList = new ArrayList<List<Integer>>();
public List<List<Integer>> levelOrder(TreeNode root) {
checkFun01(root);
return resList;
}
public void checkFun01(TreeNode root){
if(root==null) return;
Queue<TreeNode> que=new LinkedList<TreeNode>();
que.offer(root);//加入节点
while(!que.isEmpty()){//终止条件
int len =que.size();//当前层数 元素的数量
List<Integer> itemList=new ArrayList<Integer>();
while(len>0){
TreeNode temp=que.poll();
itemList.add(temp.val);//结果子列表加入值
if(temp.left!=null) que.offer(temp.left);//加入左节点
if(temp.right!=null) que.offer(temp.right);
len--;//遍历下一个节点
}
resList.add(itemList);//结果列表加入子列表
}
}
}
时间复杂度:O( n**)**;(遍历整棵树)
空间复杂度:O( n**);**(使用一个结果子列表,和一个列表)
递归法
java
class Solution {
//1.确定递归函数的参数和返回值
public List<List<Integer>> resList = new ArrayList<List<Integer>>();
public List<List<Integer>> levelOrder(TreeNode root) {
checkFun02(root,0);
return resList;
}
public void checkFun02(TreeNode root, int deep){
if(root==null) return;//2.确定递归终止条件
//3.确定单层递归的逻辑
deep++;//层级
if(resList.size()<deep){//利用list的索引值进行层级界定
List<Integer> item=new ArrayList<Integer>();
resList.add(item); //当层级增加时,list的Item也增加
}
resList.get(deep-1).add(root.val);//get 层级
checkFun02(root.left,deep);//递归左子树
checkFun02(root.right,deep);//递归右子树
}
}
时间复杂度:O( n**)**;(遍历整棵树)
空间复杂度:O( n**);**(使用一个结果子列表,和一个列表)
Leetcode226.翻转二叉树
题目链接:226.翻转二叉树
大佬视频讲解:翻转二叉树视频讲解
个人思路
遍历二叉树,将每个节点的左右孩子交换一下
解法
这道题关键在于遍历顺序,这道题目使用前序遍历,后序遍历和层序遍历都可以,唯独中序遍历不方便,因为中序遍历会把某些节点的左右孩子翻转了两次
递归法(DFS)
java
class Solution {
public TreeNode invertTree(TreeNode root) {//1.确定递归函数的参数和返回值
if (root == null) {//2.确定终止条件
return null;
}
//3.确定单层递归的逻辑
invertTree(root.left);//后序遍历:左右中(根)
invertTree(root.right);
swapChildren(root);
return root;
}
private void swapChildren(TreeNode root) {
TreeNode tmp = root.left;
root.left = root.right;
root.right = tmp;
}
}
时间复杂度:O(n);(遍历整棵树)
空间复杂度:O(n);(使用临时节点来换位)
迭代法(BFS)
java
class Solution {
public TreeNode invertTree(TreeNode root) {
if (root == null) {return null;}
ArrayDeque<TreeNode> deque = new ArrayDeque<>();//队列进行层序遍历
deque.offer(root);
while (!deque.isEmpty()) {
int size = deque.size();
while (size-- > 0) {//遍历各层的各个节点
TreeNode node = deque.poll();
swap(node);//交换节点的左右子树
if (node.left != null) deque.offer(node.left);
if (node.right != null) deque.offer(node.right);
}
}
return root;
}
public void swap(TreeNode root) {
TreeNode temp = root.left;
root.left = root.right;
root.right = temp;
}
}
时间复杂度:O(n);(遍历整棵树)
空间复杂度:O(n);(使用队列进行层序遍历和临时节点来换位)
Leetcode101. 对称二叉树
题目链接:101. 对称二叉树
大佬视频讲解:对称二叉树视频讲解
个人思路
将二叉树分成两半一边为左子树A,一边为右子树B,然后就对比 A节点的左边和B节点的右边,A节点的右边和B节点的左边,都相等就对称了
解法
递归法
因为要遍历两棵树而且要比较内侧和外侧节点 ,所以一个树的遍历顺序是左右中 ,一个树的遍历顺序是右左中。
递归三部曲
1.确定递归函数的参数和返回值
因为要比较的是根节点的两个子树是否是相互翻转的,参数就是左子树节点和右子树节点。返回值为布尔类型。
2.确定终止条件
要比较两个节点数值相不相同,要把两个节点为空的情况分清楚,不然后面比较数值的时候就会操作空指针了。
节点为空的情况有:
- 1.左节点为空,右节点不为空,不对称,return false
- 左不为空,右为空,不对称 return false
- 左右都为空,对称,返回true
此时已经排除掉了节点为空的情况,那么剩下的就是左右节点不为空:左右都不为空,比较节点数值,不相同就return false
把以上情况都排除之后,剩下的就是 左右节点都不为空,且数值相同的情况。
3.确定单层递归的逻辑
处理 左右节点都不为空,且数值相同的情况。
1.比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
2.比较内侧是否对称,传入左节点的右孩子,右节点的左孩子。
如果左右都对称就返回true ,有一侧不对称就返回false 。
java
public boolean isSymmetric1(TreeNode root) {
return compare(root.left, root.right);
}
private boolean compare(TreeNode left, TreeNode right) {1.确定递归函数的参数和返回值
2.确定终止条件
//处理节点为空的4种情况
if (left == null && right != null) {
return false;
}
if (left != null && right == null) {
return false;
}
if (left == null && right == null) {
return true;
}
if (left.val != right.val) {
return false;
}
3.确定单层递归的逻辑
// 递归比较二叉树外侧
boolean compareOutside = compare(left.left, right.right);
// 递归比较内侧
boolean compareInside = compare(left.right, right.left);
return compareOutside && compareInside;//都为真则为真
}
时间复杂度:O(n);(遍历二叉树)
空间复杂度:O(1);(无使用额外空间)
迭代法
java
public boolean isSymmetric3(TreeNode root) {
Queue<TreeNode> deque = new LinkedList<>();
deque.offer(root.left);
deque.offer(root.right);
while (!deque.isEmpty()) {
TreeNode leftNode = deque.poll();
TreeNode rightNode = deque.poll();
if (leftNode == null && rightNode == null) {
continue;
}
// 将其他三个判断条件合并
if (leftNode == null || rightNode == null || leftNode.val != rightNode.val) {
return false;
}
//左子树的左节点和右子树的右节点
deque.offer(leftNode.left);
deque.offer(rightNode.right);
//左子树的右节点和右子树的左节点
deque.offer(leftNode.right);
deque.offer(rightNode.left);
}
return true;
}
时间复杂度:O(n);(遍历二叉树)
空间复杂度:O(n);(使用队列)