java面试算法题(2)

来源:互联网 发布:美工培训班多少钱 编辑:程序博客网 时间:2024/05/16 14:45

引言

本篇博文中核心是对单链表的数据操作,从不同角度分析问题,寻求不同的结果。分享给大家。

题目

存在一个单链表,寻找这个单链表倒数第K的元素。比如{1->2->3->4->5},倒数第2个元素为4。

分析一

最容易想到的是:我们自己先遍历一遍链表,获取链表的总长度为N,那么我们就知道倒数第K的元素位置就是N-K。然后重新遍历该链表,寻找N-K位置的元素就可以了。

实现代码一

package com.brickworkers;/** *  * @author Brickworker * Date:2017年6月28日下午2:25:55  * 关于类Example.java的描述:在单链表中寻找倒数第K个元素 * Copyright (c) 2017, brcikworker All Rights Reserved. */public class Example<T> {    //定义一个头节点    Node head = null;    //定义一个内部类,表示一个链表的节点    class Node{        private T t;        Node next;        public Node(T t) {            this.t = t;        }    }    //链表插入数据    public void insert(T t){        Node node = new Node(t);        //如果头结点是空,那就是首次插入        if(head == null){            head = node;        }else {            //如果头结点不为空,那么寻找最后为空的位置插入            Node p = head;            while(p.next!= null){                p = p.next;            }            p.next = node;        }    }    //展示链表状态    public void print(){        Node p = head;        while(p!=null){            System.out.print(p.t + "->");            p = p.next;        }        System.out.print("null\n");    }    //打印倒数第K个元素    //分析一    public void analysis1(int K){    if(K < 1){            throw new IllegalArgumentException("K参数不合法");        }        //先遍历一次链表获得总长度        int count = 0;        Node p = head;        while(p !=null ){            count ++;            p = p.next;        }        //再遍历一遍链表获得对于的值        count = count - K;//把倒数转成顺序遍历的位置        p = head;        while(count > 0){            p = p.next;            count --;        }        System.out.println("倒数第" + K +"个元素为:" + p.t);    }     public static void main(String[] args) {        //构建一个链表        Example<Integer> example = new Example<Integer>();        example.insert(1);        example.insert(2);        example.insert(3);        example.insert(4);        example.insert(5);        //打印链表结构        example.print();        //获取倒数第三个元素        example.analysis1(3);    }}////1->2->3->4->5->null//倒数第3个元素为:3

在上面的代码中,构建了一个自定义的单链表结构。这种解决方式是最容易想到,而且代码写起来也非常顺利。

分析二

第二种容易想到的办法就是蛮力法,如果从链表中的某一个节点开始,遍历K个元素到达链表尾部,那么这个开始的节点就是倒数第K个节点。那么实现上来说,我们就需要对每一个节点尝试进行遍历K个元素,查看是否到达链表尾部就可以了。比如开始的节点为C,那么只要保证C.(K-1).next !=null && C.K.next ==null的时候C就是我们要寻找的节点。但是在代码中,我们从头开始遍历,只需要恰好出现最后一个为null的时候就可以确认倒数第K个数了。

实现代码二

//为了节省篇幅,只提供核心代码,其余代码和实现代码一是一样的,只需要把下面代码嵌入使用就可以    public void analysis2(int K){        if(K < 1){            throw new IllegalArgumentException("K参数不合法");        }        //从头开始遍历链表        Node p = head;        while(getIndex(p, K) != null){            p = p.next;        }        System.out.println("倒数第" + K +"个元素为:" + p.t);    }    //获取当前位置后k个数    private Node getIndex(Node n, int k){        while(k > 0){            n = n.next;            k --;        }        return n;    }

在上述的代码中,其实时间复杂度比分析一种的还要高,假如存在n个元素,那么最差时间复杂度就是O(kn),效率比较低下,但是可以拓展思维能力。

分析三

还有一个最高效解决这个问题的办法:指针追击。设置两个指针,其中一个指针先行k步,然后两个指针同时向前移动。当先行的指针为null的时候,那么后面这个指针所指向的元素就是倒数第K个元素。

实现代码三

public void analysis3(int K){        if(K < 1){            throw new IllegalArgumentException("K参数不合法");        }        //设立两个指针        Node fast = head;//快行K步        Node slow = head;        while(K > 0){            //中途出现了null值,一般考虑K值不合法的情况            if(fast == null){                throw new IllegalArgumentException("K参数不合法");            }            fast = fast.next;            K --;        }        //两个指针同时向前移动        while(fast != null){            fast = fast.next;            slow = slow.next;        }        System.out.println("倒数第" + K +"个元素为:" + slow.t);    }

这种方法效率最高,但是不易想到,但是如果有看过关于类似指针追击,找环这样问题的,应该还是可以运用的上。它只需要遍历一遍链表就可以处理完结果。

总结

在链表中做数据处理的时候,尤其是查找特定条件下的元素,都可以考虑一下多指针是否可以解决问题,往往会有很大收获。

希望对你有所帮助

原创粉丝点击