1、链表

1、两数之和

  1. public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
  2. // 使用非常常规的解法
  3. ListNode pre = new ListNode(0);
  4. ListNode cur = pre;
  5. int carry = 0;
  6. while (l1 != null || l2 != null){
  7. int num1 = l1 == null ? 0 : l1.val;
  8. int num2 = l2 == null ? 0 : l2.val;
  9. // 获取总和
  10. int sum = num1 + num2 + carry;
  11. // 取余
  12. cur.next = new ListNode(sum % 10);
  13. carry = sum / 10;
  14. // 下一次循环
  15. cur = cur.next;
  16. if (l1 != null){
  17. l1 = l1.next;
  18. }
  19. if (l2 != null){
  20. l2 = l2.next;
  21. }
  22. }
  23. if (carry == 1){
  24. cur.next = new ListNode(carry);
  25. }
  26. return pre.next;

2、删除链表倒数节点

 public ListNode removeNthFromEnd(ListNode head, int n) {
         ListNode dummy = new ListNode(0, head);
        ListNode first = head;
        ListNode second = dummy;
        for (int i = 0; i < n; ++i) {
            first = first.next;
        }
        while (first != null) {
            first = first.next;
            second = second.next;
        }
        second.next = second.next.next;
        ListNode ans = dummy.next;
        return ans;
    }

3、合并两个有序列表

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null) {
            return l2;
        }
        else if (l2 == null) {
            return l1;
        }
        else if (l1.val < l2.val) {
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        }
        else {
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }

    }

4、合并n个有序链表

public ListNode mergeKLists(ListNode[] lists) {
        return merge(lists, 0, lists.length - 1);
    }

    public ListNode merge(ListNode[] lists, int l, int r) {
        if (l == r) {
            return lists[l];
        }
        if (l > r) {
            return null;
        }
        int mid = (l + r) >> 1;
        return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
    }

    public ListNode mergeTwoLists(ListNode a, ListNode b) {
        if (a == null || b == null) {
            return a != null ? a : b;
        }
        ListNode head = new ListNode(0);
        ListNode tail = head, aPtr = a, bPtr = b;
        while (aPtr != null && bPtr != null) {
            if (aPtr.val < bPtr.val) {
                tail.next = aPtr;
                aPtr = aPtr.next;
            } else {
                tail.next = bPtr;
                bPtr = bPtr.next;
            }
            tail = tail.next;
        }
        tail.next = (aPtr != null ? aPtr : bPtr);
        return head.next;
    }

5、两两交换链表的节点

  public ListNode swapPairs(ListNode head) {
        if(head == null || head.next == null){
            return head;
        }
        ListNode next = head.next;
        head.next = swapPairs(next.next);
        next.next = head;
        return next;
    }

6、K个一组翻转链表

public ListNode rotateRight(ListNode head, int k) {
        if(head == null || head.next == null) return head;
        if(k == 0) return head;
        ListNode tail = head, newtail = head;
        ListNode newhead;
        int n = 1;
        // 原来的尾结点指向原来的头结点,形成环
        while(tail.next != null){
            tail = tail.next;
            n++;
        }
        tail.next = head;
        // 找到断开环的位置
        for(int i = 0; i < (n - k % n - 1); i++){
            newtail = newtail.next;
        }
        // 新的头结点指向断开环的位置
        newhead = newtail.next;
        newtail.next = null;

        return newhead;
    }

7、旋转链表

public ListNode rotateRight(ListNode head, int k) {
        ListNode temp = head;
        ListNode left = head;
        ListNode right = head;
        if (head == null) return null;
        // 计算链表长度
        ListNode count = head;
        int n = 1;
        while (count.next != null){
            count = count.next;
            n++;
        }
        k = k % n;
        if (k <=0 || head.next == null) return head;
        // 双指针 找到k的位置
        for (int i = 0; i<k && right.next != null;i++){
            right = right.next;
        }
        // 将链表成环
        while (right.next != null){
            left = left.next;
            // 为k的位置
            right = right.next;
        }
        ListNode resNode = left.next;
        right.next = temp;
        left.next = null;
        return resNode;
    }

8、删除重复的节点(不留)

 public ListNode deleteDuplicates(ListNode head) {
        // 没有节点或者只有一个节点,必然没有重复元素
        if (head == null || head.next == null) return head;

        // 当前节点和下一个节点,值不同,则head的值是需要保留的,对head.next继续递归
        if (head.val != head.next.val) {
            head.next = deleteDuplicates(head.next);
            return head;
        } else {
            // 当前节点与下一个节点的值重复了,重复的值都不能要。
            // 一直往下找,找到不重复的节点。返回对不重复节点的递归结果
            ListNode notDup = head.next.next;
            while (notDup != null && notDup.val == head.val) {
                notDup = notDup.next;
            }
            return deleteDuplicates(notDup);
        }
    }

9、删除重复的节点(留)

public ListNode deleteDuplicates(ListNode head) {
        if (head == null) return null;
        ListNode right = head;
        while (right.next != null){
            if (right.val == right.next.val){
                right.next = right.next.next;
            }else{
                right = right.next;
            }
        }
        return head;
    }

10、翻转链表

 public ListNode reverseBetween(ListNode head, int left, int right) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode pre = dummy;
        ListNode slow = dummy;
        ListNode fast = dummy;
        if (head == null)return head;
        // 快指针先走一段时间
        for (int i = 0;i< right-left + 1 && fast != null;i++) fast = fast.next;
        // 慢指针走到 入前指针前一个节点
        for (int j = 0;j< left -1 && fast != null;j++){
            pre = pre.next;
            fast = fast.next;
        }
        ListNode last = fast.next;
        fast.next = null;
        ListNode leftNode = pre.next;
        pre.next = null;
        reverse(leftNode);

        // 拼接前面
        pre.next = fast;
        leftNode.next = last;
        return dummy.next;
    }

    public ListNode reverse(ListNode head){
        ListNode pre = null;
        ListNode right = head;

        while (right != null){
            ListNode next = right.next;
            right.next = pre;
            pre = right;
            right = next;
        }
        return pre;
    }

11、二叉树展开为链表

 public void flatten(TreeNode root) {
        while (root != null){
            // 判断是否存在左子树
            if (root.left == null){
                root = root.right;
            }else{
                TreeNode pre = root.left;

                // 找到左子节点的最右节点
                while (pre.right != null){
                    pre = pre.right;
                }
                // 将pre 的右节点接root的右节点
                pre.right = root.right;
                // root 的右节点接root 的左节点
                root.right = root.left;

                // 下面两步为将root 到下一个节点循环
                root.left = null;
                root = root.right;
            }
        }

    }

12、复制设计链表

public Node copyRandomList(Node head) {
        if(head==null) {
            return null;
        }
        Node p = head;
        //第一步,在每个原节点后面创建一个新节点
        //1->1'->2->2'->3->3'
        while(p!=null) {
            Node newNode = new Node(p.val);
            newNode.next = p.next;
            p.next = newNode;
            p = newNode.next;
        }
        p = head;
        //第二步,设置新节点的随机节点
        while(p!=null) {
            if(p.random!=null) {
                p.next.random = p.random.next;
            }
            p = p.next.next;
        }
        Node dummy = new Node(-1);
        p = head;
        Node cur = dummy;
        //第三步,将两个链表分离
        while(p!=null) {
            cur.next = p.next;
            cur = cur.next;
            p.next = cur.next;
            p = p.next;
        }
        return dummy.next;
    }

13、排序链表

public ListNode insertionSortList(ListNode head) {
        if (head == null) return head;

        ListNode dummy = new ListNode(-1);
        dummy.next = head;

        // 定义前后节点来查找
        ListNode lastNode = head;
        ListNode curr = head.next;

        while (curr != null){
            if (lastNode.val <= curr.val){
                lastNode = lastNode.next;
            }else{
                ListNode pre = dummy;
                // 找到最佳位置
                while (pre.next.val <= curr.val){
                    pre = pre.next;
                }
                // 后面删除当前节点
                lastNode.next = curr.next;
                // 在找到的位置处插入
                curr.next = pre.next;
                pre.next = curr;
            }
            curr = lastNode.next;
        }
        return dummy.next;

    }

14、相交链表

 public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == null || headB == null) return null;
        // 两个链表 循环2次就是相交点
        ListNode curA = headA;
        ListNode curB = headB;

        while (curA != curB){
            curA = curA == null ? headB : curA.next;
            curB = curB == null ? headA : curB.next;
        }
        return curA;
    }

public ListNode getIntersectionNode(ListNode head1, ListNode head2) {
        if (head1 == null || head2 == null)return null;
        ListNode curr1 = head1;
        ListNode curr2 = head2;
        int n = 0;
        while (curr1.next != null){
            n++;
            curr1 = curr1.next;
        }
        while (curr2.next != null){
            n--;
            curr2 = curr2.next;
        }
        if (curr1 != curr2)return null;
        curr1 = n > 0 ? head1 : head2;
        curr2 = curr1 == head1 ? head2 : head1;
        n = Math.abs(n);
        while (n != 0){
            n--;
            curr1 = curr1.next;
        }
        while (curr1 != curr2){
            curr1 = curr1.next;
            curr2 = curr2.next;
        }
        return curr1;
    }

15、翻转链表元素

 public ListNode reverseList(ListNode head) {
        if (head == null || head.next == null) return head;

        // 返回最后一个
        ListNode curr = reverseList(head.next);

        // 将指针逆转  下一个的next指向当前这一个
        head.next.next = head;

        head.next = null;

        return curr;

    }

16、回文链表

 public boolean isPalindrome(ListNode head) {
        if(head == null || head.next == null) {
            return true;
        }
        ListNode slow = head, fast = head;
        ListNode pre = head, prepre = null;
        while(fast != null && fast.next != null) {
            pre = slow;
            slow = slow.next;
            fast = fast.next.next;
            pre.next = prepre;
            prepre = pre;
        }
        if(fast != null) {
            slow = slow.next;
        }
        while(pre != null && slow != null) {
            if(pre.val != slow.val) {
                return false;
            }
            pre = pre.next;
            slow = slow.next;
        }
        return true;
    }


 // 也是使用栈  n/2 时间复杂度
    public static boolean isPalindrome2(Node head){
        if (head == null || head.next == null)return true;
        Node right = head.next;
        Stack<Node> stack = new Stack<>();
        Node cur = head;
        // 快慢指针
        while (cur.next != null && cur.next.next != null){
            right = right.next;
            cur = cur.next.next;
        }
        while (right != null){
            stack.push(right);
            right = right.next;
        }
        while (!stack.isEmpty()){
            if (head.value != stack.pop().value){
                return false;
            }
            head = head.next;
        }
        return true;
    }

2、树

1、是否为平衡二叉树

class Node {
        int value;
        Node left;
        Node right;

        public Node(int value) {
            this.value = value;
        }
    }

    public static class ReturnType{
        public boolean isBalanced;
        public int height;

        public ReturnType(boolean isBalanced, int height) {
            this.isBalanced = isBalanced;
            this.height = height;
        }
    }

    public static boolean isBalanced(Node head){
        return process(head).isBalanced;
    }

    // 递归过程
    private static ReturnType process(Node head) {
        if (head == null){
            return new ReturnType(true, 0);
        }
        // 判断左边是否为平衡二叉树
        ReturnType leftData = process(head.left);
        ReturnType rightData = process(head.right);
        // 下面是条件判断
        int height = Math.max(leftData.height,rightData.height) + 1;
        boolean isBalanced = leftData.isBalanced && rightData.isBalanced
                && Math.abs(leftData.height - rightData.height) <2;
        return new ReturnType(isBalanced,height);
    }

2、是否为搜索二叉树

// 中序遍历  判断是否为搜索二叉树
    public static boolean checkBST2(Node head){
        System.out.println("in-order");
        if (head != null){
            Stack<Node> stack = new Stack<>();
            int preValue = Integer.MIN_VALUE;
            while (!stack.isEmpty() || head != null){
                if (head != null){
                    stack.push(head);
                    head = head.left;
                }else {
                    head = stack.pop();
                    if (head.value <= preValue){
                        return false;
                    }else {
                        preValue = head.value;
                    }
                    head = head.right;
                }
            }
        }
        return true;
    }

3、遍历二叉树

class Node {
        int value;
        Node left;
        Node right;

        public Node(int value) {
            this.value = value;
        }
    }

    public static void proOrderUnRecur(Node head) {
        System.out.println("pre-order");
        if (head != null) {
            Stack<Node> stack = new Stack<>();
            stack.add(head);
            while (!stack.isEmpty()) {
                head = stack.pop();
                // 先入右再入左
                System.out.print(head.value + " ");
                if (head.right != null) {
                    stack.push(head.right);
                }
                if (head.left != null) {
                    stack.push(head.left);
                }
            }
        }
        System.out.println();
    }

    // 中序遍历
    public static void inOrderRecur(Node head){
        System.out.println("in-order");
        if (head != null){
            Stack<Node> stack = new Stack<>();
            while (!stack.isEmpty() || head != null){
                if (head != null){
                    stack.push(head);
                    head = head.left;
                }else {
                    head = stack.pop();
                    System.out.print(head.value + " ");
                    head = head.right;
                }
            }
        }
        System.out.println();
    }

    // 后序遍历
    public static void posOrderUnRecur(Node head) {
        System.out.println("pos-order");
        if (head != null) {
            Stack<Node> s1 = new Stack<>();
            Stack<Node> s2 = new Stack<>();
            s1.push(head);
            while (!s1.isEmpty()) {
                head = s1.pop();
                s2.push(head);
                if (head.left != null) {
                    s1.push(head.left);
                }
                if (head.right != null) {
                    s1.push(head.right);
                }
            }
            while (!s2.isEmpty()){
                System.out.print(s2.pop()+" ");
            }
        }
        System.out.println();
    }

4、序列化

public static class Node{
        public int value;
        public Node left;
        public Node right;

        public Node(int value) {
            this.value = value;
        }
    }

    // 以head为头来序列化
    public static String serialByPre(Node head){
        if (head == null){
            return "#_";
        }
        String res = head.value + "_";
        res += serialByPre(head.left);
        res += serialByPre(head.right);
        return res;
    }

    public static Node reconByPreString(String preStr){
        String[] values = preStr.split("_");
        Queue<String> queue = new LinkedList<>();
        for (int i = 0; i < values.length; i++) {
            queue.add(values[i]);
        }
        return reconPreOrder(queue);
    }

    private static Node reconPreOrder(Queue<String> queue) {
        String value = queue.poll();
        if (value.equals("#")){
            return null;
        }
        Node head = new Node(Integer.valueOf(value));
        head.left = reconPreOrder(queue);
        head.right = reconPreOrder(queue);
        return head;
    }

5、分区

 public static class Node{
        public int value;
        public Node next;

        public Node(int data){
            this.value = data;
        }
    }

    public static Node listPartition2(Node head, int pivot){
        Node sH = null;
        Node sT = null;
        Node eH = null;
        Node eT = null;
        Node mH = null;
        Node mT = null;
        Node next = null;

        while (head != null){
            next = head.next;
            head.next = null;
            if (head.value < pivot){
                if (sH == null){
                    sH = head;
                    sT = head;
                }else {
                    sT.next = head;
                    sT = head;
                }
            }else if (head.value == pivot){
                if (eH == null){
                    eH = head;
                    eT = head;
                }else {
                    eT.next = head;
                    eT = head;
                }
            }else {
                if (mH == null){
                    mH = head;
                    mT = head;
                }else {
                    mT.next = head;
                    mT = head;
                }
            }
            head = next;
        }
        if (sT != null){
            sT.next = eH;
            eT = eT == null ? sT : eT;
        }
        if (eT != null){
            eT.next = mH;
        }
        return sH != null ? sH : (eH != null ? eH : mH);
    }

6、最大层数

public static class Node{
        public int value;
        public Node left;
        public Node right;

        public Node(int value) {
            this.value = value;
        }
    }

    // 宽度优先遍历 层次优先遍历 Node
    public static int wNode(Node head){
        if (head == null){
            return 0;
        }
        Queue<Node> queue = new LinkedList<>();
        queue.add(head);
        HashMap<Node, Integer> levelMap = new HashMap<>();
        levelMap.put(head, 1);
        int curLevel = 1;
        int curLevelNodes = 0;
        int max = Integer.MIN_VALUE;
        while (!queue.isEmpty()){
            Node cur = queue.poll();
            int curNodeLevel = levelMap.get(cur);
            if (curNodeLevel == curLevel){
                curLevelNodes++;
            }else {
                max = Math.max(max,curLevelNodes);
                curLevel++;
                curLevelNodes = 1;
            }
            if (cur.left != null){
                levelMap.put(cur.left, curNodeLevel + 1);
                queue.add(cur.left);
            }
            if (cur.right != null){
                levelMap.put(cur.right, curNodeLevel + 1);
                queue.add(cur.right);
            }
        }
        return max;
    }

7、是否为对称二叉树

public boolean isSymmetric(TreeNode root) {
        if (root == null) return true;
        return isSymmetricFun(root.left, root.right);
    }

    public boolean isSymmetricFun(TreeNode left, TreeNode right){

        // 下面两行的判断是否有一个为null 一个不为空
        if (left == null && right == null) return true;

        if (left == null || right == null) return false;

        // 比较
        if (left.val != right.val) return false;

        return isSymmetricFun(left.left, right.right) && isSymmetricFun(left.right, right.left);

    }

8、翻转二叉树

public TreeNode invertTree(TreeNode root) {
        if(root==null) {
            return null;
        }
        //将二叉树中的节点逐层放入队列中,再迭代处理队列中的元素
        LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
        queue.add(root);
        while(!queue.isEmpty()) {
            //每次都从队列中拿一个节点,并交换这个节点的左右子树
            TreeNode tmp = queue.poll();
            TreeNode left = tmp.left;
            tmp.left = tmp.right;
            tmp.right = left;
            //如果当前节点的左子树不为空,则放入队列等待后续处理
            if(tmp.left!=null) {
                queue.add(tmp.left);
            }
            //如果当前节点的右子树不为空,则放入队列等待后续处理
            if(tmp.right!=null) {
                queue.add(tmp.right);
            }

        }
        //返回处理完的根节点
        return root;
    }