输出单链表倒数第 K 个节点
要求:
输入一个单链表,输出此链表中的倒数第 K 个节点。
思路:
两个指针指向头节点,一个指针先走k-1步,两个指针一起往前走,当快指针走到最后时,慢指针指向的就是倒数第k个节点了
代码:
static ListNode findLastNode(ListNode head,int K){
if (K<=0||head==null) return null;
ListNode pre = head;//前指针
ListNode last = head;//后指针
for(int i = 0;i<K-1;i++){
if (pre!=null) pre = pre.next;
else return null;
}
while(pre.next!=null){
pre = pre.next;
last = last.next;
}
return last;
}
反转链表
要求:
把链表反转
思路:
遍历整个链表,在第一个开始逐渐移除并添加到新的链表,返回最后得到的新链表
代码:
//反转链表
static ListNode reverse(ListNode head){
if (head==null) return null;
//新节点需要连接的节点指针
ListNode pre = null;
while(head!=null){
ListNode newNode = head.next;
head.next = pre;
pre = head;
head = newNode;
}
return pre;
}
补充:
另外一个方法:遍历原链表,把节点存到栈,出栈重新连接成新的链表;
判断链表是否有环
要求:
判断链表是否有环
思路:
快慢指针法,两个指针一个一次走一步,一个一次走两步,当两指针相遇时,证明有环返回结果,最后当慢指针==null时证明无环
代码:
//判断链表是否有环
static boolean circleList(ListNode head){
ListNode slow = head;//慢指针,一次走一步
ListNode fast = head;//快指针,一次走两步
while(fast.next!=null&&slow!=null){
slow = slow.next;
fast = fast.next.next;
//当他们相等时证明链表必定有环,快指针在环中多跑了n圈最后把慢指针“"追上了"
if (slow==fast) return true;
}
return false;
}
补充:
另外一个方法,遍历链表,把遍历过的节点放到set里面,出现新放的节点已经在set里出现过了,证明有环
找链表中环的入口
要求:
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
思路:
同样是快慢指针,快慢指针当他们能相遇时,证明有环,而且他们在环中相遇,快指针比慢指针多跑了k圈
设快指针走了2n步,慢指针走了n步,环节点数为r,所以2n = n + k * r,k为快指针走过的环的圈数
所以得:n = k * r
设头节点到环的入口处的长度是x,入口处到相遇的位置为y,相遇处到入口处位置为z,可得:
上面等式左边的n = x+y,
右边的 k * r = (k-1)* r +y+z
得 x = (k-1)* r + z;
所以用其中一个指针指向头结点,两个指针一起走,相遇的时候就是刚好走完了x到达了入口处
代码:
//找到链表环的入口
static ListNode circleList1(ListNode head){
ListNode slow = head;//慢指针,一次走一步
ListNode fast = head;//快指针,一次走两步
while(slow!=null&&fast.next!=null){
slow = slow.next;
fast = fast.next.next;
//当他们相等时证明链表必定有环,快指针在环中多跑了n圈最后把慢指针“"追上了"
if (slow==fast) break;
}
//不相遇证明没有环,返回null
if (slow!=fast) return null;
//用其中一个指针指向头结点
slow = head;
while(slow!=fast){
//两个指针一起走
slow = slow.next;
fast = fast.next;
}
//当他们相遇的时候,相遇的节点就是环的入口处
return slow;
}