2020.12.05
1.前中后序 递归/非递归 实现
一、使用栈模拟递归实现过程
先序/中序
public List preinOrder2(TreeNode root){
if(root==null)
return;
Stack<TreeNode> s=new Stack<>();
List list = new LinkedList();
while(root!=null || !s.isEmpty()){
//不断往左子树方向走,每走一次就将当前节点保存到栈中
//这是模拟递归的调用
if(root != null){
list.add(root.val); //这里访问顺序是先序
s.push(root);
root = root.left;
//当前节点为空,说明左边走到头了,从栈中弹出节点并保存
//然后转向右边节点,继续上面整个过程
}else{
root = s.pop();
list.add(root.val); //这里访问顺序是中序
root = root.right;
}
}
}
后序(模拟递归实现)
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if (root == null) {
return res;
}
Deque<TreeNode> stack = new LinkedList<TreeNode>();
TreeNode prev = null;
while (root != null || !stack.isEmpty()) {
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
if (root.right == null || root.right == prev) {
res.add(root.val);
prev = root;
root = null;
} else {
stack.push(root);
root = root.right;
}
}
return res;
}
}
后序(利用前序实现「根-左-右」—> 「右-左-根」—> 「左-右-根」)
public List postorder(TreeNode root){
TreeNode node = new TreeNode();
Stack stack = new Stack();
List list = new LinkedList();
while(!stack.isEmpty() || root!=null){
if(root != null){
//头插法
List.addFirst(root.val);
stack.push(root);
//优先访问右子树
root = root.right;
}else {
root = stack.pop();
root = root.left;
}
}
return list;
}
颜色标记法模板
其核心思想如下:
- 使用颜色标记节点的状态,新节点为白色,已访问的节点为灰色。
- 如果遇到的节点为白色,则将其标记为灰色,然后将其右子节点、自身、左子节点依次入栈。
- 如果遇到的节点为灰色,则将节点的值输出
class Solution {
class ColorNode {
TreeNode node;
String color;
public ColorNode(TreeNode node,String color){
this.node = node;
this.color = color;
}
}
public List<Integer> inorderTraversal(TreeNode root) {
if(root == null) return new ArrayList<Integer>();
List<Integer> list = new ArrayList<>();
Stack<ColorNode> stack = new Stack<>();
stack.push(new ColorNode(root,"white"));
while(!stack.empty()){
ColorNode cn = stack.pop();
if(cn.color.equals("white")){
// 入栈顺序 对应于访问结果顺序(这里为中序,对应 右 根 左)
if(cn.node.right != null) stack.push(new ColorNode(cn.node.right,"white"));
stack.push(new ColorNode(cn.node,"gray"));
if(cn.node.left != null)stack.push(new ColorNode(cn.node.left,"white"));
}else{
list.add(cn.node.val);
}
}
return list;
}
}
另一种奇技淫巧,直接判断栈元素是否为TreeNode
public List<Integer> inorderTraversal(TreeNode root) {
Stack<Object> stack = new Stack<>();
List<Integer> list = new ArrayList<>();
if (root == null)
return list;
stack.push(root);
while (!stack.isEmpty()) {
Object pop = stack.pop();
if (pop instanceof TreeNode) {
// 入栈顺序 对应于访问结果顺序(这里为中序,对应 右 根 左)
TreeNode treeNode = (TreeNode) pop;
if (treeNode.right != null) {
stack.push(treeNode.right);
}
stack.push(new Integer(treeNode.val));
if (treeNode.left != null) {
stack.push(treeNode.left);
}
} else {
list.add((Integer)pop);
}
}
return list;
}
链表
1.两两交换链表中节点 (leetcode24)
思路:可以使用迭代或者递归实现
迭代实现:
新建哑结点nHead
,令nHead.next = head
,令 temp
表示当前到达的节点,初始时 temp = nHead
。每次需要交换 temp
后面的两个节点即可,如果 temp 的后面没有节点或者只有一个节点,则没有更多的节点需要交换,因此结束交换。否则,获得 temp 后面的两个节点 node1 和 node2,通过更新节点的指针关系实现两两交换节点。
public ListNode swapPairs(ListNode head) {
if (head == null || head.next == null)
return head;
ListNode nHead = new ListNode(-1);
nHead.next = head;
ListNode temp = nHead;
while (temp.next != null && temp.next.next != null) {
ListNode nNext = temp.next.next;
temp.next.next = nNext.next;
nNext.next = temp.next;
temp.next = nNext;
temp = nNext.next;
}
return nHead.next;
}
递归实现:
终止条件为head == null || head.next == null;
递归思路就是假设head.next.next后面已经完成两两交换,并返回,即temp = swapPairs(head.next.next);
则单次递归执行逻辑为:ListNode newHead = head.next; head.next = temp;newHead.next = head;
class Solution {
public ListNode swapPairs(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode newHead = head.next;
head.next = swapPairs(newHead.next);
newHead.next = head;
return newHead;
}
}
2.反转链表||(leetcode92)
输入: 1->2->3->4->5->NULL, m = 2, n = 4
输出: 1->4->3->2->5->NULL
反转从位置m到n的链表。思想:在第m节点的前一个位置(这里指向1)设为pre节点,利用cur指针(这里指向2)依次将cur节点的后置节点插入到pre后面,执行逻辑为:ListNode nxt = cur.next;cur.next = nxt.next;nxt.next = pre.next;pre.next = nxt;
public ListNode reverseBetween(ListNode head, int m, int n) {
if (head == null) return null;
ListNode pre = new ListNode(-1);
ListNode nHead = pre;
pre.next = head;
for (int i=1; i<m; i++) {
pre = pre.next;
}
ListNode cur = pre.next;
for (int i=m; i<n; i++) {
ListNode nxt = cur.next;
cur.next = nxt.next;
nxt.next = pre.next;
pre.next = nxt;
}
return nHead.next;
}