剑指offer 16-20

16 合并两个链表

  输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

有两种方法:一种是递归,一种是非递归

public class mergeTwoList_16 {
    public static void main(String[] args) {
        link4 l1 = new link4();
        link4 l2 = new link4();
        for(int i = 0; i <= 7; i++) {
            l1.add(i);
            l2.add(i+3);
        }
        mergeTwoList_16 merge = new mergeTwoList_16();
        ListNode4 node = merge.Merge2(l1.root, l2.root);
        while(node != null) {
            System.out.print(node.val+" ");
            node = node.next;
        }
    }
    //递归版本
     public ListNode4 Merge(ListNode4 l1,ListNode4 l2) {
         if(l1 == null) {
             return l2;
         }
         if(l2 == null) {
             return l1;
         }
         if(l1.val <= l2.val) {
             l1.next = Merge(l1.next, l2);
             return l1;
         }else {
             l2.next =Merge(l1, l2.next);
             return l2;
         }
     }
     //非递归
     public ListNode4 Merge2(ListNode4 l1,ListNode4 l2) {
         ListNode4 pre = new ListNode4(-1);
         ListNode4 cur =pre;
         while(l1 != null && l2 != null) {
             if(l1.val <= l2.val) {
                 cur.next = l1;
                 l1 = l1.next;
             }else {
                 cur.next = l2;
                 l2 = l2.next;
             }
             cur = cur.next;
         }
         if(l1 != null) cur.next = l1;
         if(l2 != null) cur.next = l2;
         return pre.next;
     }
}
class link4{
    ListNode4 root;
    public void add(int val) {
        ListNode4 listNode = new ListNode4(val);
        if(this.root == null) {
            this.root = listNode;
        }else {
            this.root.add(listNode);
        }
    }
}
class ListNode4{
    int val;
    ListNode4 next;
    public ListNode4(int val) {
        this.val = val;
    }
    public void add(ListNode4 listNode) {
        if(this.next == null) {
            this.next = listNode;
        }else {
            this.next.add(listNode);
        }
    }
    
}

17 树的子结构

  输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

基本思路就是遍历大树,找到与子结构跟节点相同的节点,然后传入判断函数进行遍历比较

public class substructureOfTree_17 {
    public static void main(String[] args) {
        substructureOfTree_17 s = new substructureOfTree_17();
        TreeNode2 root1 = new TreeNode2(1);
        TreeNode2 node1 = new TreeNode2(2);
        TreeNode2 node2 = new TreeNode2(3);
        TreeNode2 node3 = new TreeNode2(4);
        TreeNode2 node4 = new TreeNode2(5);
        TreeNode2 root2 = new TreeNode2(2);
        TreeNode2 node5 = new TreeNode2(4);
        TreeNode2 node6 = new TreeNode2(5);
        root1.left = node1;
        root1.right = node2;
        node1.left = node3;
        node1.right = node4;
        root2.left = node5;
        root2.right = node6;
        boolean flag = s.HasSubtree(root1, root2);
        System.out.println(flag);
    }
    //遍历大树
    public boolean HasSubtree(TreeNode2 root1,TreeNode2 root2) {
        //当Tree1和Tree2都不为零的时候,才进行比较。否则直接返回false
        if(root1 == null || root2 == null) {
            return false;
        }
        //如果找到与子树相同根的值
        if(root1.val == root2.val) {
            //以这个根节点为为起点判断是否包含Tree2
            if(judge(root1,root2)) {
                return true;
            }
        }
        //如果找不到,那么就再去root的左儿子或者右儿子当作起点,去判断时候包含Tree2
        return HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2);
    }
    public boolean judge(TreeNode2 node1,TreeNode2 node2) {
         //如果Tree2已经遍历完了都能对应的上,返回true
        if(node2 == null) {
            return true;
        }
         //如果Tree2还没有遍历完,Tree1却遍历完了。返回false
        //这两段判断代码不能交换位置
        if(node1 == null) {
            return false;
        }
         //如果其中有一个点没有对应上,返回false
        if(node1.val != node2.val) {
            return false;
        }
         //如果根节点对应的上,那么就分别去子节点里面匹配
        return judge(node1.left,node2.left) && judge(node1.right,node2.right) ;
    }
}
class TreeNode2{
    int val;
    TreeNode2 left;
    TreeNode2 right;
    public TreeNode2(int val) {
        this.val = val;
    }
}

18 二叉树的镜像

操作给定的二叉树,将其变换为源二叉树的镜像。

 两种方法:递归与非递归

递归:交换左右子树的节点,然后递归调用该方法。

非递归:借助队列

import java.util.LinkedList;
import java.util.Queue;

public class mirror_18 {

    public static void main(String[] args) {
        mirror_18 mirror = new mirror_18();
        TreeNode3 root = new TreeNode3(8);
        TreeNode3 node1 = new TreeNode3(6);
        TreeNode3 node2 = new TreeNode3(10);
        TreeNode3 node3 = new TreeNode3(5);
        TreeNode3 node4 = new TreeNode3(7);
        TreeNode3 node5 = new TreeNode3(9);
        TreeNode3 node6 = new TreeNode3(11);
        root.left = node1;
        root.right = node2;
        node1.left = node3;
        node1.right = node4;
        node2.left = node5;
        node2.right = node6;
        mirror.Mirror2(root);
         root.preOrder();
    }
    //递归
    public void Mirror(TreeNode3 root) {
        if(root == null) {
            return;
        }
        TreeNode3 temp = root.left;
         root.left = root.right;
         root.right = temp;
         Mirror(root.left);
         Mirror(root.right);
        
    }
    //非递归
    public void Mirror2(TreeNode3 root) {
        Queue<TreeNode3> queue = new LinkedList<>();
        TreeNode3 temp ,cur;
        queue.offer(root);
        int len = queue.size();
        for(int i = 0; i < len; i++) {
            cur = queue.poll();
            temp = cur.left;
            cur.left = cur.right;
            cur.right = temp;
            if(cur.left != null) queue.offer(cur.left);
            if(cur.left != null) queue.offer(cur.right);
             len = queue.size();
        }
    }

}
class TreeNode3{
    int val;
    TreeNode3 left;
    TreeNode3 right;
    public TreeNode3(int val) {
        this.val = val;
    }
    public void preOrder() {
        System.out.print(this.val+" ");
        if(this.left != null) {
            this.left.preOrder();
        }
        if(this.right != null) {
            this.right.preOrder();
        }
    }
}

19 顺时针打印矩阵

  输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

分析

简单来说,就是不断地收缩矩阵的边界
定义四个变量代表范围,up、down、left、right

    1. 向右走存入整行的值,当存入后,该行再也不会被遍历,代表上边界的 up 加一,同时判断是否和代表下边界的 down 交错
    2. 向下走存入整列的值,当存入后,该列再也不会被遍历,代表右边界的 right 减一,同时判断是否和代表左边界的 left 交错
    3. 向左走存入整行的值,当存入后,该行再也不会被遍历,代表下边界的 down 减一,同时判断是否和代表上边界的 up 交错
    4. 向上走存入整列的值,当存入后,该列再也不会被遍历,代表左边界的 left 加一,同时判断是否和代表右边界的 right 交错
import java.util.ArrayList;

public class clockwisePrintMatrix_19 {

    public static void main(String[] args) {
        int[][] matrix = {{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};
        clockwisePrintMatrix_19 print = new clockwisePrintMatrix_19();
        ArrayList<Integer> res = print.printMatrix(matrix);
        System.out.println(res.toString());
        
    }
    public ArrayList<Integer> printMatrix(int [][] matrix) {
        ArrayList<Integer> list = new ArrayList<Integer> ();
        if(matrix == null) {
            return list;
        }
        int up = 0;
        int down = matrix.length-1;
        int left = 0;
        int right = matrix[0].length-1;
        while(true) {
            //最上面一行
            for(int col = left; col <= right; col++) {
                list.add(matrix[up][col]);
            }
            //向下逼近
            up++;
            //判断是否越界
            if(up > down) {
                break;
            }
            //最右边一行
            for(int row = up; row <= down ;row++) {
                list.add(matrix[row][right]);
            }
            //向左逼近
            right--;
            //判断是否越界
            if(left > right) {
                break;
            }
            //最下面以一行
            for(int col = right; col >= left; col--) {
                list.add(matrix[down][col]);
            }
            //向上逼近
            down--;
            //判断是否越界
            if(up > down) {
                break;
            }
            //最左边一行
            for(int row = down; row >= up ;row--) {
                list.add(matrix[row][left]);
            }
            //向右逼近
            left++;
            //判断是否越界
            if(left > right) {
                break;
            }
        }
        return list;
    }

}

20 栈的压入、弹出

  输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)序列

猜你喜欢

转载自www.cnblogs.com/lgh544/p/12966131.html