两两交换链表中的元素
- 这个题要求两个一对交换,这个过程主要是:指针指向的变化,操作节点的边界问题
- 操作节点:这个节点应该要求是两个交换的节点的前一个节点,假设是0,那么改变的时候就是1->3,2->1,0->2这样的指针变化,既然是前一个节点,为了方便,依旧是设置虚拟头节点
- 边界条件:如果是奇数,cur.next.next为空结束,如果是偶数cur.next为空结束(偶数这里因为到不了cur.next.next为空这个条件,但是加上这个条件也没什么影响,所以这里直接用两个条件的&&)
- 指针变化的时候注意顺序:将需要指向的元素给存下来
public ListNode swap(ListNode head) {
ListNode dummy = new ListNode(0,head);
ListNode cur = dumy;
while(cur.next != null && cur.next.next != null) {
ListNode temp = cur.next;
cur.next = cur.next.next;
ListNode temp1 = cur.next.next;
cur.next.next = temp;
temp.next = temp1;
cur = cur.next.next;
}
return dummy.next;
}
移除链表倒数第N个节点
- 快慢指针,需要一个虚拟头节点,因为删除head的时候也需要找到head前面一个元素dummy
- 计算从dummy到null,需要整个链表长度size+1步,倒数第n个节点相当于从null向前走n步,相当于从dummy向前走size+1-n步,也就是slow向前走size+1-n步,所以快指针先向前走n步,然后快慢指针再一起向前走size+1-n步(fast == null),就可以到达要删除的元素。但是我们需要的是前一个元素,所以fast应该先向前走n+1步。
public ListNode delete(ListNode head,int n) {
ListNode dummy = new ListNode (0,head);
ListNode fast = dummy;
ListNode slow = dummy;
for(int i = 0;i < n+1;i++){
fast = fast.next;
}
while(fast != null ){
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return dummy.next;
}
环形链表II
- 快慢指针,fast走两步,slow走一步,如果能相遇,说明有环。
- 快指针相对于慢指针的速度是1,所以在环上不停的遍历,快指针肯定能追上慢指针。
- 环形的入口:0--入口:x;入口到相遇位置:y;相遇位置到入口:z;
慢指针走了:x+y
快指针走了:x+n(y+z)+y
2(x+y) = x+n(y+z)+y
x+y = n(y+z)
x = (n-1)(y+z)+z 也就是x是等于相遇位置到入口加上不定数量的环的长度的,所以如果slow从head开始,fast从相遇位置开始,每人走一步,一定可以在入口处相遇
public ListNode cycle(ListNode head) {
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if(slow == fast) {
slow = head;
while(slow != fast) {
slow = slow.next;
fast = fast.next;
}
return slow;
}
}
return null;
}