剑指offer——链表中倒数第k个结点

来源:互联网 发布:linux 拷贝文件 编辑:程序博客网 时间:2024/06/10 22:46

1. 问题描述

输入一个链表,输出该链表中倒数第k个结点。

2. 解决方案

遇到链表,那么肯定是在考察数据结构的相关知识。对于一个单链表来讲,其实还是没那么复杂。另外就是在进行手写数据结构的链表、队列、栈、树、图的时候,一定要注意鲁棒性,包括下标和指针的使用。

对于这题来讲,首先想到的可能是先统计一遍,然后再往回倒腾k个即可。但是这样的话,如果使用java自带的链表先恢复一遍可以。也可以使用一个栈来进行实施。如果只能想到这种方法,建议转换到java中标准的数据结构,这样,在细节操作上,不会出现失误,不然手写代码,容易出现BUG。

下面要讲的这个算法,是预估法,其实对于时间复杂度来讲,可能与上面的遍历一遍以后再回溯差距不大,毕竟上面方法时间复杂度仅为N+K,且KN,因此其上限不会超过2N。而下面要介绍的预估法,其时间复杂度为N,它好就好在遇到不正确的输入的时候,可以提前结束算法,提高程序的鲁棒性。

这种预估算法简单来讲就像是在量一个长度为N的布,我们只需要量到N-K长即可。而我们只有一个长度为K的尺子,这时候,自然要从左往右依次移动尺子,一直移动到尺子右端到达底部,而尺子左端就是我们要的那个界限了。

具体算法如下:

public static ListNode FindKthToTail(ListNode head,int k) {        //先向前看k个,如果看不到,返回Null        ListNode temp=head;        ListNode tailed=head;        //如果输入的是非法的数。        if(k<1){            return null;        }        //把尺子先伸长到指定长度        for(int i=0;i<k-1;i++){            //如果尺子比布要长,找不到            if(tailed==null){                return null;            }            else{                tailed=tailed.next;            }        }        if(tailed==null){            return null;        }        //如果正好这么长,返回开始的。        else if(tailed.next==null){            return temp;        }        else{            while(true){                //到达底端,返回尺子开头的位置。                if(tailed.next==null){                    return temp;                }                //否则就移动尺子。                else{                    tailed=tailed.next;                    temp=temp.next;                }            }        }    }

3. 一点思考

其实这种预估法在很多地方都有应用,这也是算法优化的一个方向。例如在操作系统中对于页面置换的预估,一个称为真预估,真正预测在将来时间内发生的事,但这是不可能的,因此被称为是optimal算法,只为了检验算法的优劣。另一个是假预估,它通过过去发生的来近似拟合将来发生的事。这一点也被证实是十分有用的。

这个想法也是一直贯穿整个算法的过程。还需要多加理解。

0 0
原创粉丝点击