1898 2018-12-01 2020-06-25

前言:牛客网剑指Offer编程题55~60题。

一、链表中环的入口结点

1、题目描述

考点链表,给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

2、我的代码

        public ListNode EntryNodeOfLoop(ListNode pHead) {
            ArrayList<ListNode> list = new ArrayList<>();
            while (pHead != null) {
                if (list.contains(pHead)) {
                    return pHead;
                }
                list.add(pHead);
                pHead = pHead.next;
            }
            return null;
        }

3、别人的代码

还是看下大神的代码吧,心累啊。

第一步,找环中相汇点。分别用p1,p2指向链表头部,p1每次走一步,p2每次走二步,直到p1==p2找到在环中的相汇点。
第二步,找环的入口。接上步,当p1==p2时,p2所经过节点数为2x,p1所经过节点数为x,设环中有n个节点,p2比p1多走一圈有2x=n+x; n=x;可以看出p1实际走了一个环的步数,再让p2指向链表头部,p1位置不变,p1,p2每次走一步直到p1==p2; 此时p1指向环的入口
public class Solution { 
    ListNode EntryNodeOfLoop(ListNode pHead){
        if(pHead == null || pHead.next == null)
            return null;
        ListNode p1 = pHead;
        ListNode p2 = pHead;
        while(p2 != null && p2.next != null ){
            p1 = p1.next;
            p2 = p2.next.next;
            if(p1 == p2){
                p2 = pHead;
                while(p1 != p2){
                    p1 = p1.next;
                    p2 = p2.next;
                }
                if(p1 == p2)
                    return p1;
            }
        }
        return null;
    }
}

二、删除链表中重复的结点

1、题目描述

考点链表,在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5。

2、我的代码

一看到这题,我就想到了LinkedHashMap,哈哈,不能这么搞。

public ListNode deleteDuplication(ListNode pHead) {
    if (pHead == null) {
        return null;
    }
    ListNode head = new ListNode(0);
    ListNode root = head;
    ListNode cur = pHead;
    ListNode nex = cur.next;
    boolean isInCheck = false;
    while (nex != null) {
        if (cur.val != nex.val) {
            if (!isInCheck) {
                System.out.println(head.val + "正常添加" + cur.val);
                head.next = cur;
                head = head.next;
                cur = cur.next;
                nex = nex.next;
                head.next = null;
            } else {
                cur = nex;
                nex = nex.next;
                isInCheck = false;
            }
        } else {
            isInCheck = true;
            nex = nex.next;
        }
    }
    if (cur.next == null && !isInCheck) {
        head.next = cur;
    }
    return root.next;
}

三、二叉树的下一个结点

1、题目描述

考点树,给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

2、我的代码

static class FiftySeven {
    public static class TreeLinkNode {
        int val;
        TreeLinkNode left = null;
        TreeLinkNode right = null;
        TreeLinkNode next = null;
        TreeLinkNode(int val) {
            this.val = val;
        }
    }

    boolean findTarget = false;
    TreeLinkNode target = null;

    public TreeLinkNode GetNext(TreeLinkNode pNode) {
        if (pNode == null) {
            return null;
        }
        TreeLinkNode node = pNode;
        while (pNode.next != null) {
            pNode = pNode.next;
        }
        TreeLinkNode root = pNode;
        traverse(root, node);
        return target;
    }

    private void traverse(TreeLinkNode root, TreeLinkNode node) {
        if (root == null || target != null) {
            return;
        }
        traverse(root.left, node);
        if (findTarget) {
            target = root;
            findTarget = false;
        }
        if (root == node) {
            findTarget = true;
        }
        traverse(root.right, node);
    }

    private static void test() {
        TreeLinkNode node1 = new TreeLinkNode(8);
        TreeLinkNode node2 = new TreeLinkNode(6);
        TreeLinkNode node3 = new TreeLinkNode(10);
        TreeLinkNode node4 = new TreeLinkNode(5);
        TreeLinkNode node5 = new TreeLinkNode(7);
        TreeLinkNode node6 = new TreeLinkNode(9);
        TreeLinkNode node7 = new TreeLinkNode(11);
        node1.left = node2;
        node1.right = node3;
        node2.left = node4;
        node2.right = node5;
        node3.left = node6;
        node3.right = node7;
        System.out.println(new FiftySeven().GetNext(node1).val);
    }
}

四、对称的二叉树

1、题目描述

考点树,请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

2、我的代码

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

boolean isSymmetrical(TreeNode pRoot) {
    if (pRoot == null) {
        return true;
    }
    ArrayList<TreeNode> list = new ArrayList<>();
    traverse(pRoot, list);
    if (list.size() % 2 == 0 || list.get(list.size() / 2) != pRoot) {
        return false;
    }
    while (list.size() != 1) {
        if (list.remove(0).val != (list.remove(list.size() - 1).val)) {
            return false;
        }
    }
    return true;
}

private void traverse(TreeNode node, ArrayList<TreeNode> list) {
    if (node.left != null) {
        traverse(node.left, list);
    }
    System.out.println(node.val);
    list.add(node);
    if (node.right != null) {
        traverse(node.right, list);
    }
}

哈哈,答案错误:您提交的程序没有通过所有的测试用例,case通过率为90.00%。第一次觉得,完全通过一次测试,也不容易啊。

3、别人的代码

别人的代码就是好--系列博客,哈哈。

boolean isSymmetrical1(TreeNode pRoot) {
    if (pRoot == null) {
        return true;
    }
    return isSymmetrical1(pRoot.left, pRoot.right);
}

boolean isSymmetrical1(TreeNode t1, TreeNode t2) {
    if (t1 == null && t2 == null) {
        return true;
    }
    if (t1 != null && t2 != null) {
        return t1.val == t2.val && isSymmetrical1(t1.left, t2.right) && isSymmetrical1(t1.right, t2.left);
    }
    return false;
}

4、别人的代码2

膜拜吧,凡人。

boolean isSymmetricalDFS(TreeNode pRoot) {
    if (pRoot == null) return true;
    Stack<TreeNode> s = new Stack<>();
    s.push(pRoot.left);
    s.push(pRoot.right);
    while (!s.empty()) {
        TreeNode right = s.pop();//成对取出
        TreeNode left = s.pop();
        if (left == null && right == null) continue;
        if (left == null || right == null) return false;
        if (left.val != right.val) return false;
        //成对插入
        s.push(left.left);
        s.push(right.right);
        s.push(left.right);
        s.push(right.left);
    }
    return true;
}

boolean isSymmetricalBFS(TreeNode pRoot) {
    if (pRoot == null) return true;
    Queue<TreeNode> s = new LinkedList<>();
    s.offer(pRoot.left);
    s.offer(pRoot.right);
    while (!s.isEmpty()) {
        TreeNode right = s.poll();//成对取出
        TreeNode left = s.poll();
        if (left == null && right == null) continue;
        if (left == null || right == null) return false;
        if (left.val != right.val) return false;
        //成对插入
        s.offer(left.left);
        s.offer(right.right);
        s.offer(left.right);
        s.offer(right.left);
    }
    return true;
}

五、按之字形顺序打印二叉树

1、题目描述

考点树,请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

2、别人的代码

自己有点没思路,索性直接看别人的代码了。

public static ArrayList<ArrayList<Integer>> Print(TreeNode pRoot) {
    int layer = 1;
    //s1存奇数层节点
    Stack<TreeNode> s1 = new Stack<TreeNode>();
    s1.push(pRoot);
    //s2存偶数层节点
    Stack<TreeNode> s2 = new Stack<TreeNode>();

    ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>();

    while (!s1.empty() || !s2.empty()) {
        if (layer%2 != 0) {
            ArrayList<Integer> temp = new ArrayList<Integer>();
            while (!s1.empty()) {
                TreeNode node = s1.pop();
                if(node != null) {
                    temp.add(node.val);
                    System.out.print(node.val + " ");
                    s2.push(node.left);
                    s2.push(node.right);
                }
            }
            if (!temp.isEmpty()) {
                list.add(temp);
                layer++;
                System.out.println();
            }
        } else {
            ArrayList<Integer> temp = new ArrayList<Integer>();
            while (!s2.empty()) {
                TreeNode node = s2.pop();
                if(node != null) {
                    temp.add(node.val);
                    System.out.print(node.val + " ");
                    s1.push(node.right);
                    s1.push(node.left);
                }
            }
            if (!temp.isEmpty()) {
                list.add(temp);
                layer++;
                System.out.println();
            }
        }
    }
    return list;
}

写得真是好啊。

3、别人的代码2

思路也是不错的。

public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
    ArrayList<ArrayList<Integer>> ret = new ArrayList<>();
    if (pRoot == null) {
        return ret;
    }
    ArrayList<Integer> list = new ArrayList<>();
    LinkedList<TreeNode> queue = new LinkedList<>();
    queue.addLast(null);//层分隔符
    queue.addLast(pRoot);
    boolean leftToRight = true;
     
    while (queue.size() != 1) {
        TreeNode node = queue.removeFirst();
        if (node == null) {//到达层分隔符
            Iterator<TreeNode> iter = null;
            if (leftToRight) {
                iter = queue.iterator();//从前往后遍历
            } else {
                iter = queue.descendingIterator();//从后往前遍历
            }
            leftToRight = !leftToRight;
            while (iter.hasNext()) {
                TreeNode temp = (TreeNode)iter.next();
                list.add(temp.val);
            }
            ret.add(new ArrayList<Integer>(list));
            list.clear();
            queue.addLast(null);//添加层分隔符
            continue;//一定要continue
        }
        if (node.left != null) {
            queue.addLast(node.left);
        }
        if (node.right != null) {
            queue.addLast(node.right);
        }
    }     
    return ret;
}

六、把二叉树打印成多行

1、题目描述

考点树,从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

2、别人的代码

public class Solution {
    ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) {
        ArrayList<ArrayList<Integer>> list = new ArrayList<>();
        depth(pRoot, 1, list);
        return list;
    }
     
    private void depth(TreeNode root, int depth, ArrayList<ArrayList<Integer>> list){
        if(root == null) return;
        if(depth > list.size())
            list.add(new ArrayList<Integer>());
        list.get(depth -1).add(root.val);
         
        depth(root.left, depth + 1, list);
        depth(root.right, depth + 1, list);
    }
}

3、别人的代码2

ArrayList> Print(TreeNode pRoot) {
    //存放结果
    ArrayList> arrayLists = new ArrayList();
    if (pRoot == null) {
        return arrayLists;
    }
    //使用队列,先进先出
    Queue queue = new LinkedList();
    //存放每行的列表
    ArrayList arrayList = new ArrayList();
    //记录本层打印了多少个
    int start = 0;
    //记录下层打几个
    int end = 1;
    queue.add(pRoot);
    while (!queue.isEmpty()) {
        TreeNode temp = queue.remove();
        //添加到本行的arrayList
        arrayList.add(temp.val);
        start++;
        //每打印一个节点,就把此节点的下一层的左右节点加入队列,并记录下一层要打印的个数
        if (temp.left != null) {
            queue.add(temp.left);
        }
        if (temp.right != null) {
            queue.add(temp.right);
        }
        //判断本层打印是否完成
        if (start == end) {
            //此时的queue中存储的都是下一层的节点,则end即为queue大小
            end = queue.size();
            start = 0;
            //把arrayList添加到结果列表arrayLists中
            arrayLists.add(arrayList);
            //重置arrayList
            arrayList = new ArrayList();
        }
    }
    return arrayLists;
}

稍稍有点急,稳住吧,还有最后一篇。

总访问次数: 271次, 一般般帅 创建于 2018-12-01, 最后更新于 2020-06-25

进大厂! 欢迎关注微信公众号,第一时间掌握最新动态!