美文网首页
判断链表中是否有环以及其中的扩展衍生问题

判断链表中是否有环以及其中的扩展衍生问题

作者: just_like_you | 来源:发表于2019-08-06 07:57 被阅读0次

记录关于链表的面试题

判断单链表中是否有环?

  • 直接遍历解法,每遍历一个元素都要和前面遍历过的所有元素进行比较,时间复杂度比较高为O(n^2)
    //使用遍历校验看单链表是否有环,时间复杂度O(n^2) ,空间复杂度O(1)
    public boolean checkIsRing() {
        Node pre;
        Node cur = head;
        while (cur != null) {
            pre = cur;
            cur = cur.next;
            Node compare = head;
            while (compare != null && compare != pre) {
                if (compare == cur) {
                    return true;
                }
                compare = compare.next;
            }
        }
        return false;
    }
  • HashMap空间换时间解法
    //使用HashMap保存历史链表,降低时间复杂度O(n) 空间复杂度变为O(n)
    public boolean checkIsRingWithHashMap() {
        HashMap<Node, Integer> store = new HashMap<>();
        Node cur = head;
        int count = 1;
        while (cur != null) {
            if (store.containsKey(cur)) {
                return true;
            }
            store.put(cur, count++);
            cur = cur.next;
        }
        return false;
    }
  • 快慢指针,采用追击问题的解决方式来操作。若有环则快指针会和慢指针相遇
    //使用快慢指针 时间复杂度O(n) ,空间复杂度O(1)
    public boolean checkIsRingWithQuickAndSlowNode() {
        Node slow = head;
        Node quick = head;
        while (slow != null && quick != null) {
            slow = slow.next;
            quick = quick.next.next;
            if (slow == quick) {
                return true;
            }
        }
        return false;
    }

有环那么环的长度是多少?

该问题,统计两次相遇之间的遍历次数即可

    //返回单链表的环长度
    public int getRingLength() {
        int cycle = 0;
        int count = 0;
        Node slow = head;
        Node quick = head;
        while (quick != null && quick.next != null) {
            slow = slow.next;
            quick = quick.next.next;
            count++;
            if (slow == quick) {
                if (cycle == 1) {
                    return count;
                }
                cycle++;
                count = 0;
            }
        }
        return 0;
    }

环的起始节点是什么?

这个问题不好想到关联关系,为了解释,引用<漫画算法>里面的一张图

判断环的起始节点
由图我们我们很简单的可以通过行走的距离得到2(D+S1)=D+2S1+S2,从而得到一个重要结论,那就是D=S2,也就是头结点到入环节点的位置等于首次相遇到入环点的位置,那么我们只要在相遇的时候,将任一节点移动到头结点,然后快慢指针速度变为1即可,下面为实现源码
    //获取入环节点
    public Node getRingStartNode() {
        Node slow = head;
        Node quick = head;
        while (quick != null && quick.next != null) {
            slow = slow.next;
            quick = quick.next.next;
            if (slow == quick) {
                //相遇了,让slow到头结点
                slow = head;
                break;
            }
        }

        if (quick != null && quick.next != null) {
            while (slow != quick) {
              //修改快慢节点的速度
                slow = slow.next;
                quick = quick.next;
            }
        }
        return slow;
    }

相关文章

网友评论

      本文标题:判断链表中是否有环以及其中的扩展衍生问题

      本文链接:https://www.haomeiwen.com/subject/jtmbdctx.html