31.栈的压入和弹出
栈辅助法,两个汉诺塔
class Solution {
public boolean validateStackSequences(int[] pushed, int[] popped) {
//辅助栈方法
Stack<Integer> stack = new Stack<>();
int i = 0;
for(int num : pushed) {
stack.push(num); // num 入栈
while(!stack.isEmpty() && stack.peek() == popped[i]) { // 循环判断与出栈
stack.pop();
i++;
}
}
return stack.isEmpty();
}
}
32-I 从上到下打印二叉树
可以使用层序遍历,但要求的是int[]数据类型输出,所以,考虑结果用什么容器存放比较重要
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int[] levelOrder(TreeNode root) {
//层序遍历
if(root == null) return new int[0];
Queue<TreeNode> queue = new LinkedList<>(){{ add(root); }};//定义并初始化
ArrayList<Integer> ans = new ArrayList<>();
while(!queue.isEmpty()) {
TreeNode node = queue.poll();
ans.add(node.val);
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
}
int[] res = new int[ans.size()];
for(int i = 0; i < ans.size(); i++)
res[i] = ans.get(i);
return res;
}
}
直接使用双链表输出,需要把双链表转化为int[]
class Solution {
public int[] levelOrder(TreeNode root) {
//层序遍历,但是要求是输出int[]
Queue<TreeNode> queue = new LinkedList<>();
List<List<Integer>> ans = new ArrayList<>();
if(root !=null) queue.add(root);
while(!queue.isEmpty()) {
int size = queue.size();
List<Integer> tmp = new ArrayList<>();
for(int i =0;i<size;i++){
TreeNode node = queue.poll();//返回之后再删除
tmp.add(node.val);
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
}
ans.add(tmp);
}
ArrayList<Integer> collect2 = ans.stream().collect(ArrayList::new, ArrayList::addAll, ArrayList::addAll);
return collect2.stream().mapToInt(k->k).toArray();//二维链表转换成一维链表在转成一维数组输出,耗时较长,不如前一次提交的方法
}
}
32-II从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。
层序遍历,输出类型为 List<List>
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
//二叉树的层序遍历
Queue<TreeNode> queue = new LinkedList<>();
List<List<Integer>> ans = new ArrayList<>();
if(root !=null) queue.add(root);
while(!queue.isEmpty()) {
int size = queue.size();
List<Integer> tmp = new ArrayList<>();
for(int i =0;i<size;i++){
TreeNode node = queue.poll();//返回之后再删除
tmp.add(node.val);
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
}
ans.add(tmp);
}
return ans;
}
}
32-III 按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
Deque<TreeNode> deque = new LinkedList<>();
List<List<Integer>> res = new ArrayList<>();
if(root != null) deque.add(root);
while(!deque.isEmpty()) {
// 打印奇数层
List<Integer> tmp = new ArrayList<>();
for(int i = deque.size(); i > 0; i--) {
// 从左向右打印
TreeNode node = deque.removeFirst();//第一次进入就删除节点,ode不是空节点了吗?
tmp.add(node.val);
// 先左后右加入下层节点
if(node.left != null) deque.addLast(node.left);
if(node.right != null) deque.addLast(node.right);
}
res.add(tmp);
if(deque.isEmpty()) break; // 若为空则提前跳出
// 打印偶数层
tmp = new ArrayList<>();//重新构造临时数组
for(int i = deque.size(); i > 0; i--) {
// 从右向左打印
TreeNode node = deque.removeLast();
tmp.add(node.val);
// 先右后左加入下层节点
if(node.right != null) deque.addFirst(node.right);
if(node.left != null) deque.addFirst(node.left);
}
res.add(tmp);
}
return res;
}
}
33.二叉搜索树的后序遍历序列
搜索树:中序遍历是一个升序排列的数
class Solution {
public boolean verifyPostorder(int[] postorder) {
return recur(postorder, 0, postorder.length - 1);
}
boolean recur(int[] postorder, int i, int j) {
if(i >= j) return true;
int p = i;
while(postorder[p] < postorder[j]) p++; //postorder[j]是根结点
int m = p;//划分左右子树
while(postorder[p] > postorder[j]) p++; //判断右子树是否都大于根结点
return p == j && recur(postorder, i, m - 1) && recur(postorder, m, j - 1);
}
}
34.二叉树汇总和为某一值的路径(有难度)
class Solution {
LinkedList<List<Integer>> res = new LinkedList<>();
LinkedList<Integer> path = new LinkedList<>();
public List<List<Integer>> pathSum(TreeNode root, int sum) {
recur(root, sum);
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(path));//复制一个path,之后改变path,res中的path不会改变。
//为什么要new新开辟一个list
recur(root.left, tar);//前序遍历
recur(root.right, tar);
path.removeLast();
}
}
35.复杂链表的复制
map中的key表示next指针,map中的value表示random指针
class Solution {
public Node copyRandomList(Node head) {
if(head == null) return null;
Node cur = head;
Map<Node, Node> map = new HashMap<>();
// 3. 复制各节点,并建立 “原节点 -> 新节点” 的 Map 映射
while(cur != null) {
map.put(cur, new Node(cur.val)); //为什么不能直接用cur.val,因为map的value是Node类型
cur = cur.next;
}
cur = head;
// 4. 构建新链表的 next 和 random 指向
while(cur != null) {
map.get(cur).next = map.get(cur.next);//构建next指向
map.get(cur).random = map.get(cur.random);//构建random指向
cur = cur.next;
}
// 5. 返回新链表的头节点
return map.get(head);
}
}
36,二叉搜索树与双向链表
class Solution {
Node pre, head;
public Node treeToDoublyList(Node root) {
if(root == null) return null;
dfs(root);
head.left = pre; //头结点指向尾结点
pre.right = head; //尾结点指向头节点
return head;
}
void dfs(Node cur) {
//中序遍历
if(cur == null) return;
dfs(cur.left);
if(pre == null) head = cur; //cur左侧没有节点,即此时cur为双向链表中的头节点
else { //cur左侧有结点
pre.right = cur;//1->2
}
cur.left = pre;//1<-2
pre = cur;//保存cur
dfs(cur.right);
}
}