面试题23:链表中环的入口节点
题目要求:
假设一个链表中包含环,请找出入口节点。若没有环则返回null。
解题思路:
当然可以使用遍历。顺序访问,当第二次访问同一个节点时,那么那个节点就是入口节点。不过这种解法需要o(n)的空间。
能不能把空间降为o(1),时间依旧为o(n)。当然可以。这种解法的思路是:首先申请两个指针,快指针一次前进两步,慢指针一次前进一步,初始化都再链表头部。然后开始移动,如果他们指向了同一个节点,则证明有环,否则没环。当他们指向了同一个节点时,慢指针再次初始化,指向头结点。快慢指针前进步数都改为1,当他们再次指向同一个节点,这个节点就是环的入口节点。不明白的话请先看证明过程链接,然后再看我说的思路总结。
这3道连续的链表题目,解法上有一定的相似性,都是使用两个指针。碰到链表或者数组的问题,没有好的解法时可以试试这几个常见思路。
解法 | 题目 | 链接 |
---|---|---|
左右指针 | 使数组中奇数位于偶数前面/快排 | 链接 |
前后指针 | 链表中倒数第k个节点 | 链接 |
快慢指针 | 链表中环的入口节点 | 链接 |
package structure;
/**
* Created by ryder on 2017/6/13.
*/
public class ListNode<T> {
public T val;
public ListNode<T> next;
public ListNode(T val){
this.val = val;
this.next = null;
}
@Override
public String toString() {
StringBuilder ret = new StringBuilder();
ret.append("[");
for(ListNode cur = this;;cur=cur.next){
if(cur==null){
ret.deleteCharAt(ret.lastIndexOf(" "));
ret.deleteCharAt(ret.lastIndexOf(","));
break;
}
ret.append(cur.val);
ret.append(", ");
}
ret.append("]");
return ret.toString();
}
}
package chapter3;
import structure.ListNode;
/**
* Created by ryder on 2017/7/14.
* 链表中倒数第k个节点
*/
public class P134_KthNodeFromEnd {
public static ListNode<Integer> findKthToTail(ListNode<Integer> head,int k){
if(head==null||k<=0)
return null;
ListNode<Integer> slow=head,fast=head;
for(int i=0;i<k;i++){
//i==k-1,第三个测试例通不过
if(fast.next!=null || i==k-1)
fast = fast.next;
else
return null;
}
while(fast!=null){
slow = slow.next;
fast = fast.next;
}
return slow;
}
public static void main(String[] args){
ListNode<Integer> head = new ListNode<>(1);
head.next= new ListNode<>(2);
head.next.next = new ListNode<>(3);
System.out.println(findKthToTail(head,1).val);
System.out.println(findKthToTail(head,2).val);
System.out.println(findKthToTail(head,3).val);
System.out.println(findKthToTail(head,4));
}
}
运行结果
3
2
1
null