美文网首页
高级工程师面试常见数据结构与算法问题---快慢指针

高级工程师面试常见数据结构与算法问题---快慢指针

作者: 薛定谔_810a | 来源:发表于2019-06-14 17:14 被阅读0次

在面试高级和资深java工程师时,几乎百分百会涉及数据结构与算法问题,而快慢指针即考较算法,也问到来了数据 结构,是个,块面试题的熟客,那快慢指针计算未知长度的单链表的三等分点来举例。

首先给出单链表的结点的基础结构,

public class Node {

    public String data; // 结点的数据域

    public Node next; // 节点的指针域

    public Node(){

    }

    public Node(String data) {
        this.data = data;
    }

}

然后给出单链表的基础结构,和基础添加结点的方法

public class LinkList {

    private Node head;  //头结点

    //调用LinkList构造方法时初始化head
    public LinkList() {
        head = new Node();
    }

    public void addNode(Node node) {
        Node temp = head;
//     遍历寻找追后一个结点
        while (temp.next != null) {
            temp = temp.next;
        }
        temp.next = node;
    }

}

快慢指针确定单链表的长度时,需要确定单链表中是否有环。
基本思路是如果有环,那么快指针一定会在环中追上慢指针,从而相遇。实现代码如下。

   public Boolean hasCycle(LinkList linkList){
        if(head == null) {
            return false;
        }
        if(head.next == null){
            return false;
        }
        Node fast =  head.next.next;
        Node low = head.next;
        while (true){
            if(fast == null || fast.next ==null){
                return  false;
            }
            //代表快针追上慢指针,有环
            if(fast.data == low.data || fast.next == null){
                return true;
            }else {
                fast = fast.next.next;
                low = low.next;
            }

        }
    }

在判定单链表结构中无环的情况下
可以利用一个三倍速的指针快速跑完结点,从而单倍速的指针指向的就是三等分的第一个等分点。

 /**
     * 快慢指针快速寻找三等分点(单链表无环三等分点)
     * @param linkList
     */
    public void getTriSelectorNode(LinkList linkList){
        Node speed1 = linkList.head;//一倍数指针
        Node speed3 = linkList.head;//三倍速指针
        while (speed3.next != null){
            if(speed3.next.next.next != null){
                //三倍速结点存在下一轮则其他指针都按各自速度前进
                speed3 = speed3.next.next.next;
                speed1 = speed1.next;
            }else if(speed3.next.next != null){
                //三倍速结点,第,三个结点为空,第二个结点不为空 ,如长度为8的链,三倍数指针指到7,单倍数指针指向的是3,单倍数指针四舍五入加一位跳转
                speed3 = speed3.next.next;
                speed1 = speed1.next;
            }else {
                //三倍速结点,第,三个结点为空,第二个结点也为空 ,如长度为9的链,三倍数指针指到7,单倍数指针指向的是3,单倍数指针不需要跳转
                speed3 = speed3.next;
                speed1 = speed1;
            }

        }
        System.out.println(speed1.data);
    }

如果单链表中有环,可以分开计算环结点前的长度和的长度。计算方法将在代码中说明

  public int getCycleTriSelectorNode (LinkList linkList){
        Node speed1 = linkList.head;//一倍数指针
        Node speed3 = linkList.head;//三倍速指针
        while (true){
            speed1 = speed1.next;
            speed3 = speed3.next.next.next;
            if(speed1.next.data .equals(speed3.next.data)){
                //找到快慢指针
                break;
            }
        }
        //慢针走了s步,则快针走了3s,s = 环结点前的长度 + 环结点到碰撞点的步数,
        // 3s =  环结点前的长度 + 环结点到碰撞点的步数 + n*环长度(n是快结点比慢节点多跑的圈数)
        // 也就是环结点前的长度 = n*环长度 - 环结点到碰撞点的步数
        // 也就是头结点和相遇结点分别设一指针,同步(单步)前进,则最后一定相遇在环入口结点p。
        Node p = linkList.head;
        Node speed1Temp = speed1;
        int headlength = 0; // 环节点前的长度
        while (p != speed1){
            p = p.next;
            speed1Temp = speed1Temp.next;
            headlength++;
        }
        //快指针和慢指针从碰撞点开始继续往前走,再次碰撞时所用的操作数就是环的长度Length环
        int cyclelength = 0;  // 环的长度
        while (true){
            speed1 = speed1.next;
            speed3 = speed3.next.next.next;
            if(speed1.next.data .equals(speed3.next.data)){
                //找到
                break;
            }
            cyclelength++;
        }
        //计算三等分点
        return (int)(headlength+cyclelength)/3;
    }

最后将测试代码与类代码一并汇总,可以直接运行。

public class LinkList {

    private Node head;  //头结点

    //调用LinkList构造方法时初始化head
    public LinkList(){
        head = new Node();
    }

    public void addNode(Node node){
        Node temp = head;
//     遍历寻找追后一个结点
        while (temp.next != null){
            temp = temp.next;
        }
        temp.next = node;
    }

    /**
     * 判定链表中是否有环
     * @param linkList
     * @return
     */
    public Boolean hasCycle(LinkList linkList){
        if(head == null) {
            return false;
        }
        if(head.next == null){
            return false;
        }
        Node fast =  head.next.next;
        Node low = head.next;
        while (true){
            if(fast == null || fast.next ==null){
                return  false;
            }
            //代表快针追上慢指针,有环
            if(fast.data == low.data || fast.next == null){
                return true;
            }else {
                fast = fast.next.next;
                low = low.next;
            }

        }
    }


    /**
     * 快慢指针快速寻找三等分点(单链表无环三等分点)
     * @param linkList
     */
    public void getTriSelectorNode(LinkList linkList){
        Node speed1 = linkList.head;//一倍数指针
        Node speed3 = linkList.head;//三倍速指针
        while (speed3.next != null){
            if(speed3.next.next.next != null){
                //三倍速结点存在下一轮则其他指针都按各自速度前进
                speed3 = speed3.next.next.next;
                speed1 = speed1.next;
            }else if(speed3.next.next != null){
                //三倍速结点,第,三个结点为空,第二个结点不为空 ,如长度为8的链,三倍数指针指到7,单倍数指针指向的是3,单倍数指针四舍五入加一位跳转
                speed3 = speed3.next.next;
                speed1 = speed1.next;
            }else {
                //三倍速结点,第,三个结点为空,第二个结点也为空 ,如长度为9的链,三倍数指针指到7,单倍数指针指向的是3,单倍数指针不需要跳转
                speed3 = speed3.next;
                speed1 = speed1;
            }

        }
        System.out.println(speed1.data);
    }

    /**
     * 快慢指针快速寻找三等分点(单链表有环三等分点)
     * @param linkList
     */
    public int getCycleTriSelectorNode (LinkList linkList){
        Node speed1 = linkList.head;//一倍数指针
        Node speed3 = linkList.head;//三倍速指针
        while (true){
            speed1 = speed1.next;
            speed3 = speed3.next.next.next;
            if(speed1.next.data .equals(speed3.next.data)){
                //找到快慢指针
                break;
            }
        }
        //慢针走了s步,则快针走了3s,s = 环结点前的长度 + 环结点到碰撞点的步数,
        // 3s =  环结点前的长度 + 环结点到碰撞点的步数 + n*环长度(n是快结点比慢节点多跑的圈数)
        // 也就是环结点前的长度 = n*环长度 - 环结点到碰撞点的步数
        // 也就是头结点和相遇结点分别设一指针,同步(单步)前进,则最后一定相遇在环入口结点p。
        Node p = linkList.head;
        Node speed1Temp = speed1;
        int headlength = 0; // 环节点前的长度
        while (p != speed1){
            p = p.next;
            speed1Temp = speed1Temp.next;
            headlength++;
        }
        //快指针和慢指针从碰撞点开始继续往前走,再次碰撞时所用的操作数就是环的长度Length环
        int cyclelength = 0;  // 环的长度
        while (true){
            speed1 = speed1.next;
            speed3 = speed3.next.next.next;
            if(speed1.next.data .equals(speed3.next.data)){
                //找到
                break;
            }
            cyclelength++;
        }
        //计算三等分点
        return (int)(headlength+cyclelength)/3;
    }

    public static void main(String[] args) {
        LinkList linkList = new LinkList();
        for(int i = 1;i < 9; i++){
            Node node = new Node("结点"+i);
            linkList.addNode(node);
        }
//        形成环
//        linkList.head.next.next.next.next.next.next.next.next.next = linkList.head.next.next.next.next;
        if(linkList.hasCycle(linkList)){
            int triSelectorlength = linkList.getCycleTriSelectorNode(linkList);
            System.out.println("链表中------------有环");
            System.out.println("结点"+triSelectorlength);
        }else {
            System.out.println("链表中-------------无环");
            linkList.getTriSelectorNode(linkList);
        }

    }


}

相关文章

  • 高级工程师面试常见数据结构与算法问题---快慢指针

    在面试高级和资深java工程师时,几乎百分百会涉及数据结构与算法问题,而快慢指针即考较算法,也问到来了数据 结构,...

  • 面试常见问题 - 目录

    面试常见问题01 - C++相关(施工ing) 面试常见问题02 - 算法与数据结构(施工ing) 面试常见问题0...

  • 【剑指offer-双指针】

    导读 算法 | 双指针套路总结 常用的双指针技巧 算法与数据结构基础 - 双指针 目录: 面试题04. 二维数组中...

  • 快慢指针的应用

    --- 最近在刷LeetCode时,发现快慢指针在链表和查找算法中应用非常广泛,对于很多即将面试或者学习算法的同学...

  • LeetCode进阶977-双指针

    概要 双指针是一种比较常见的算法思想,在循环遍历数组时经常会用到。双指针主要有两种算法技巧:1、快慢指针(例如已发...

  • 面试 7:快慢指针法玩转链表算法面试(一)

    面试 7:面试常见的链表类算法捷径 链表是我们数据结构面试中比较容易出错的问题,所以很多面试官总喜欢在这上面下功夫...

  • 数据结构与算法 --- 1(数据结构基本概念)

    为什么要学习数据结构与算法? 这个问题其实从面试上就可以略知一二,通常,越是大的公司,对于数据结构与算法越是重视,...

  • 判断单链表环的快慢指针法

    快慢指针法 算法步骤 初始化快慢指针 循环处理,快指针走两步,慢指针走一步,直到发现环或者到达链表结尾 伪代码 环...

  • 链表篇

    有环链表判断,快慢指针 通用克隆数据结构方法 Tricky 方法

  • 算法与数据结构

    数据结构 数据结构与算法分析_Java语言描述(第2版) 算法 计算机算法基础算法导论编程之法_面试和算法心得 c...

网友评论

      本文标题:高级工程师面试常见数据结构与算法问题---快慢指针

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