1.单向反转链表

image.png

1.使用递归解决√

  1. public ListNode reverseList(ListNode head) {
  2. //终止条件
  3. if (head == null || head.next == null)
  4. return head;
  5. //保存当前节点的下一个结点
  6. ListNode next = head.next;
  7. //从当前节点的下一个结点开始递归调用
  8. ListNode reverse = reverseList(next);
  9. /*reverse是反转之后的链表,因为函数reverseList
  10. 表示的是对链表的反转,所以反转完之后next肯定
  11. 是链表reverse的尾结点,然后我们再把当前节点*/
  12. //head挂到next节点的后面就完成了链表的反转。
  13. next.next = head;
  14. //这里head相当于变成了尾结点,尾结点都是为空的,
  15. //否则会构成环
  16. head.next = null;
  17. return reverse;
  18. }
  19. -------------------------------------------------------------
  20. 自己的想法:
  21. /**
  22. * Definition for singly-linked list.
  23. * public class ListNode {
  24. * int val;
  25. * ListNode next;
  26. * ListNode() {}
  27. * ListNode(int val) { this.val = val; }
  28. * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
  29. * }
  30. */
  31. class Solution {
  32. public ListNode reverseList(ListNode head) {
  33. //定位到末结点
  34. if(head.next==null||head==null)
  35. return head;
  36. //3->4->5->1 假如当前head=node3,reverseList(head.next)=reverseList(node4)=node4=newHead
  37. ListNode newHead = reverseList(head.next);
  38. head.next.next = head;//即node4.next=node3
  39. head.next=null;//即node3.next=null 实现: node4->node3->null
  40. return newHead;
  41. }
  42. }

2.尾递归*

  1. public ListNode reverseList(ListNode head) {
  2. return reverseListInt(head, null);
  3. }
  4. private ListNode reverseListInt(ListNode head, ListNode newHead) {
  5. if (head == null)
  6. return newHead;
  7. ListNode next = head.next;
  8. head.next = newHead;
  9. return reverseListInt(next, head);
  10. }

3.使用栈解决

image.png

  1. class Solution {
  2. public ListNode reverseList(ListNode head) {
  3. Stack<ListNode> stack = new Stack<>();
  4. //将每个结点放入栈中
  5. while(head!=null){
  6. stack.push(head);
  7. head = head.next;
  8. }
  9. //若栈为空,即没有结点,返回null
  10. if (stack.isEmpty())
  11. return null;
  12. //以第一个弹出的结点为头结点
  13. ListNode node = stack.pop();
  14. ListNode newHead = node;
  15. //依次弹栈接入头结点尾后
  16. while(!stack.isEmpty()){
  17. ListNode temp = stack.pop();
  18. node.next=temp;
  19. node = node.next;
  20. }
  21. //让尾结点的next为null
  22. node.next = null;
  23. return newHead;
  24. }
  25. }

4.双链表求解

image.png

  1. class Solution {
  2. public ListNode reverseList(ListNode head) {
  3. ListNode newHead = null;
  4. while(head!=null){
  5. //先保存访问的节点的下一个节点,保存起来留着下一步访问的
  6. ListNode temp = head.next;
  7. //每次访问的原链表节点都会成为新链表的头结点,其实就是把新链表挂到访问的原链表节点的后面就行了
  8. head.next = newHead;
  9. //更新新链表
  10. newHead = head;
  11. //重新赋值,继续访问
  12. head = temp;
  13. }
  14. return newHead;
  15. }
  16. }
  17. ----------------------------------------------------------------
  18. class Solution {
  19. public ListNode reverseList(ListNode head) {
  20. ListNode newHead = null;//1-2-3-4-5
  21. while(head!=null){
  22. ListNode temp = head.next;
  23. head.next=newHead;//核心
  24. newHead=head;
  25. head=temp;
  26. }
  27. return newHead;
  28. }
  29. }

2.链表内指定区间反转

image.png

  1. import java.util.*;
  2. /*
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next = null;
  6. * }
  7. */
  8. public class Solution {
  9. /**
  10. *
  11. * @param head ListNode类
  12. * @param m int整型
  13. * @param n int整型
  14. * @return ListNode类
  15. */
  16. public ListNode reverseBetween (ListNode head, int m, int n) {
  17. //设置虚拟头节点
  18. ListNode virHead = new ListNode(-1);
  19. virHead.next =head; //virHead.next=head
  20. ListNode pre = virHead;//pre = virHead
  21. for(int i=1;i<m;i++){
  22. pre = pre.next;
  23. }//-1-1-2-3-4-5 m=2,n=4 ==>1-4-3-2-5 ==>pre=node1
  24. ListNode P1 = pre.next;//P1=node2
  25. ListNode P2;
  26. //双指针法
  27. for(int i=0;i<n-m;i++){//i<2,循环进行2次
  28. P2 = P1.next;//1:P2 = node3 2:P2 = node4
  29. P1.next = P2.next;//1:P1.next=node2.next=node4 2-4 2:node2.next=node4.next=node5 2-5
  30. P2.next = pre.next;//1:P2.next=node3.next=node2 3-2 2:node4.next=node2 4-3
  31. pre.next = P2; //1:node1.next=node3 1-3 2:node1.next=node4 1-4
  32. //第一次循环:1-3(P2)-2(P1)-4-5 第二次循环:1-4-3-2-5
  33. }
  34. return virHead.next;
  35. }
  36. }

TODO:建议画图重新温习一遍

3.链表中的节点每k个一组翻转

image.png

  1. import java.util.*;
  2. public class Solution {
  3. public ListNode reverseKGroup (ListNode head, int k) {
  4. if(k==1){
  5. return head;
  6. }
  7. int n,m=0;//①n为循环次数,m为链表总元素
  8. ListNode temp = head;
  9. while(temp!=null){
  10. temp=temp.next;
  11. m++;
  12. }
  13. n = m/k;
  14. ListNode virHead = new ListNode(-1);
  15. virHead.next=head;
  16. ListNode pre = virHead;
  17. for(int i=0;i<n;i++){ //②依次反转
  18. // if (pre.next==null){
  19. // break;
  20. // }这里用不着判断
  21. ListNode p1 = pre.next;
  22. ListNode p2;
  23. for(int j = 1; j < k;j++){//③双指针反转
  24. p2=p1.next;
  25. p1.next=p2.next;
  26. p2.next=pre.next;
  27. pre.next=p2;
  28. }
  29. pre=p1;//这一步很重要
  30. }
  31. return virHead.next;
  32. }
  33. }

4.合并两个排序的链表

image.png

public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        if (list1==null){
            return list2;
        }
        if (list2==null){
            return list1;
        }
        ListNode virHead = new ListNode(-1);
        ListNode temp = virHead;
        while(list1!=null&&list2!=null){
            if(list1.val<=list2.val){
                temp.next=list1;
                list1=list1.next;
            }else{
                temp.next=list2;
                list2=list2.next;
            }
            temp=temp.next;
        }
        temp.next=list1==null?list2:list1;
        return virHead.next;
    }
}

5.合并k个已排序的链表

image.png

树的基本算法

1.前序遍历

image.png

import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 *   public TreeNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param root TreeNode类 
     * @return int整型一维数组
     */
    public int[] preorderTraversal (TreeNode root) {
        List<Integer> list = new ArrayList();
        preorder(root,list);
        int[] tree = new int[list.size()];
        for(int i=0;i<list.size();i++){
            tree[i]=list.get(i);
        }
        return tree;
    }
    public void preorder(TreeNode root,List list){
        if(root==null){
            return;
        }
        list.add(root.val);
        preorder(root.left,list);
        preorder(root.right,list);
    }
}

2.中序遍历

public class Solution {
    public int[] inorderTraversal (TreeNode root) {
        List<Integer> list = new ArrayList();
        inorder(root,list);
        int[] tree = new int[list.size()];
        for(int i = 0;i<list.size();i++){
            tree[i] = list.get(i); 
        }
        return tree;
    }
    public void inorder(TreeNode root,List list){
        if(root==null){
            return;
        }
        inorder(root.left,list);
        list.add(root.val);
        inorder(root.right,list);
    }
}

3.后序遍历

public class Solution {
    public int[] postorderTraversal (TreeNode root) {
        List<Integer> list = new ArrayList();
        postorder(list,root);
        int[] tree = new int[list.size()];
        for(int i = 0;i<list.size();i++){
            tree[i] = list.get(i);
        }
        return tree;
    }
    public void postorder(List list,TreeNode root){
        if(root==null){
            return;
        }
        postorder(list,root.left);
        postorder(list,root.right);
        list.add(root.val);
    }
}

4.层序遍历

image.png

import java.util.*;

/*
 * public class TreeNode {
 *   int val = 0;
 *   TreeNode left = null;
 *   TreeNode right = null;
 * }
 */

public class Solution {
    /**
     * 
     * @param root TreeNode类 
     * @return int整型ArrayList<ArrayList<>>
     */
    public ArrayList<ArrayList<Integer>> levelOrder (TreeNode root) {
        ArrayList<ArrayList<Integer>> res = new ArrayList();
        if(root == null){
            return res;
        }
        Queue<TreeNode> p = new ArrayDeque();
        p.add(root);
        System.out.println(p.size());
        while(!p.isEmpty()){
            ArrayList<Integer> r = new ArrayList();
            int n = p.size();
            for(int i = 0; i < n;i++){
                //int i = 0; i < p.size();i++这里有问题,不能用p.size(),必须要声明一个变量n
                //这是因为循环内部会使队列长度发生变化
                TreeNode temp = p.poll();
                r.add(temp.val);
                if(temp.left!=null){
                    p.add(temp.left);
                }
                if(temp.right!=null){
                    p.add(temp.right);
                }
            }
            res.add(r);
        }
        return res;
    }
}

5.树的深度

image.png

public int maxDepth (TreeNode root) {
        int rDepth = 0;
        int lDepth = 0;
        int Depth = 0;
        if(root == null){
            return 0;
        }
        lDepth = maxDepth(root.left);
        rDepth = maxDepth(root.right);
        Depth = lDepth>rDepth?lDepth+1:rDepth+1;
        return Depth;
}

6.按Z形顺序打印二叉树

image.png

import java.util.*;
public class Solution {
    public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        TreeNode head = pRoot;
        ArrayList<ArrayList<Integer>> res = new ArrayList();
        if(pRoot==null){
            return res;
        }
        Queue<TreeNode> temp = new LinkedList();
        temp.offer(head);
        boolean flag = true;
        while(!temp.isEmpty()){
            ArrayList<Integer> list = new ArrayList();
            int n = temp.size();
            for(int i = 0; i< n;i++){
                TreeNode node = temp.poll();
                list.add(node.val);
                if(node.left!=null){
                    temp.offer(node.left);
                }
                if(node.right!=null){
                    temp.offer(node.right);
                }
            }
            //flag为真的时候不反转
            if(!flag){
                Collections.reverse(list);
            }
            res.add(list);
            flag = !flag;
        }
        return res;
    }
}

7.二叉树和为某一值的路径

image.png

import java.util.*;
public class Solution {
    public boolean hasPathSum (TreeNode root, int sum) {
        if(root == null){
            return false;
        }
        if(root.left==null&&root.right==null&&sum-root.val==0){
            return true;
        }
        return hasPathSum(root.left,sum-root.val) || hasPathSum(root.right,sum-root.val);
    }
}

8.二叉搜索树与双向链表的转化

image.png

import java.util.ArrayList;
import java.util.List;
public class Solution {
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree == null){
            return null;
        }
        ArrayList<TreeNode> list = new ArrayList<>();
        // 中序遍历
        Convert(list,pRootOfTree);
        // 构建双向链表
        return Convert(list);
    }
    public void Convert(ArrayList<TreeNode> list,TreeNode root){
        if(root != null){//这里的判断不能少,否则会报空指针异常
            Convert(list,root.left);
            list.add(root);
            Convert(list,root.right);
        }
    }

    /*
    这是核心代码,假设链表为 2 4 6 
    转化为双向链表为 2 <-> 4 <-> 6 
    */
    public TreeNode Convert(ArrayList<TreeNode> list){
        TreeNode head = list.get(0);
        TreeNode cur = head;
        for (int i=1;i< list.size();++i){
            TreeNode node=list.get(i);
            node.left=cur;
            cur.right=node;
            cur=node;
        }
        return head;
    }
}

9.判断二叉树是否对称

image.png

import java.util.*;
public class Solution {
    boolean isSymmetrical(TreeNode pRoot) {
        if(pRoot==null) return true;//判断根节点是否为空
        return isSymmetrical(pRoot.left,pRoot.right);
    }
    boolean isSymmetrical(TreeNode left,TreeNode right){
        if(left==null&&right==null) return true;
        if(left==null||right==null) return false;//左右结点一个有一个无
        //以下是两个结点都有的情况
        return left.val==right.val
            &&isSymmetrical(left.left,right.right)
            &&isSymmetrical(left.right,right.left);
    }
}

10.合并二叉树

image.png

import java.util.*;
public class Solution {
    public TreeNode mergeTrees (TreeNode t1, TreeNode t2) {
        //前序递归
        if(t1==null&&t2==null) return t1;
        if(t1==null||t2==null) return t1==null?t2:t1;
        t1.val=t1.val+t2.val;
        t1.left = mergeTrees(t1.left,t2.left);
        t1.right = mergeTrees(t1.right,t2.right);
        return t1;
    }
}

11.二叉树的镜像

image.png

import java.util.*;
public class Solution {
    public TreeNode Mirror (TreeNode pRoot) {
        if(pRoot==null) return pRoot;
        if(pRoot.left==null&&pRoot.right==null) return pRoot;//这里的作用在于少一次无意义的交换
        //前序递归
        TreeNode temp = pRoot.left;
        pRoot.left = pRoot.right;
        pRoot.right = temp;
        Mirror(pRoot.left);
        Mirror(pRoot.right);
        return pRoot;
    }
}

12.判断是否为二叉搜索树

image.png

import java.util.*;
public class Solution {
    public int min = Integer.MIN_VALUE;
    public boolean isValidBST (TreeNode root) {
        //一提到二叉搜索树,就要想到中序遍历
        if(root==null) return true;
        //递归左子树
        if(!isValidBST(root.left)) return false;
        //核心代码:如果min>当前节点值,则不是二叉搜索树,反之则将当前结点值赋值给min
        if(min>root.val){
            return false;
        }else{
            min = root.val;
        }
        //递归右子树
        if(!isValidBST(root.right)) return false;
        return true;
    }
}

13.判断是否为完全二叉树

image.png

import java.util.*;
public class Solution {
    public boolean isCompleteTree (TreeNode root) {
        if(root == null) return true;
        Queue<TreeNode> queue = new LinkedList();
        queue.add(root);
        boolean flag = true;
        while(!queue.isEmpty()){
            TreeNode temp = queue.poll();
            //很巧妙判断结点为null的下一个节点是否有值,若为null,continue,q为空退出循环
            //最终返回true,若不为null,执行if(flag==false)语句,最终返回false
            if(temp == null){
                flag = false;
                continue;
            }
            if(flag==false) return false;
            //如果是层序遍历,这里应该先判断左右结点是否为空,不为空才放入队列
            //而这里,加入最后一个节点后没有结点,也会放入两个null。
            //两个为null的情况,返回true;先有结点后为null的情况,返回true;先为null后有值才返回false
            queue.add(temp.left);
            queue.add(temp.right);
        }
        return true;
    }
}

14.判断是否为平衡二叉树

image.png

import java.util.*;
public class Solution {
    public boolean IsBalanced_Solution(TreeNode root) {
        if(root == null) return true;
        return Math.abs(Depth(root.right)-Depth(root.left))<=1&&
            IsBalanced_Solution(root.right)&&
            IsBalanced_Solution(root.left);
    }
    public int Depth(TreeNode node){
        //依然可以运用后续遍历的思想
        if(node == null) return 0;
        return Math.max(Depth(node.right),Depth(node.left))+1;
    }
}

15.二叉搜索树的最近公共祖先

image.png

import java.util.*;
public class Solution {
     public int lowestCommonAncestor (TreeNode root, int p, int q) {
         //两个都大于root结点,则向右递进
        if(root.val<p&&root.val<q){
            return lowestCommonAncestor(root.right,p,q);
        }
         //两个都小于root结点,则向左递进
         if(root.val>p&&root.val>q){
            return lowestCommonAncestor(root.left,p,q);
         }
         return root.val;
    }
}

16.在二叉树中找到两个节点的最近公共祖先

image.png

//稍微有点难想,建议画图思考
import java.util.*;
public class Solution {
    public int lowestCommonAncestor (TreeNode root, int o1, int o2) {
        return helper(root,o1,o2).val;
    }

    private TreeNode helper(TreeNode root,int p,int q){
        if(root==null) return root;
        if(root.val==p||root.val==q) return root;
        TreeNode left = helper(root.left,p,q);
        TreeNode right = helper(root.right,p,q);
        if(left==null) return right;
        if(right==null) return left;
        return root;
    }
}