题目描述
解法一:双指针迭代----改变相邻两个节点的值
- 如果 head == null || head.next == null ,无需交换,直接返回 head 即可;
- 如果步骤1假设不成立,则设置两个指针slow、fast,初始化为
ListNode slow = head;
ListNode fast = head.next; - 进入循环,交换两个指针所指向节点的值,交换成功后再将其进行后移;
- 循环结束后返回head。
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null)
return head;
ListNode slow = head;
ListNode fast = head.next;
while(fast != null){
int temp = fast.val;
fast.val = slow.val;
slow.val = temp;
if(fast.next != null){
slow = fast.next;
fast = slow.next;
}else
break;
}
return head;
}
解法二:双指针迭代----改变节点本身
因为涉及到节点指针域的改变,为了处理方便(避免额外节点的处理),很自然地想到了设置虚拟头节点(dummyHead),并设置 cur 指针指向dummyHead,作为当前指针的指向,然后就可以通过 cur 设置双指针slow、fast,这样就可以在循环中进行指针域的改变了。
但是还有一个重要的问题,假设链表是1->2->3->4,slow指向1,fast指向2,改变a和b的指向,于是就变成2->1,但是1指向谁呢?1是不能指向2的next(形成了环),因为接下来还要进行上述同样的操作,所以1应该指向3,那3怎么获得呢?可以在未改变指针域之前先将3保存下来,即2.next,这就需要额外的指针temp进行保存操作了,所以第一次交换后,链表就变成了2->1->3->4。循环体末尾将 cur 指向 slow ,这样才算完成一次循环,接下来就是进行下一次的交换,直至交换结束。
public ListNode swapPairs(ListNode head) {
ListNode dummyHead = new ListNode(0);
dummyHead.next = head;
ListNode cur = dummyHead;
while(cur.next != null && cur.next.next != null){
ListNode slow = cur.next;
ListNode fast = slow.next;
ListNode temp = fast.next;
cur.next = fast;
fast.next = slow;
slow.next = temp;
cur = slow;
}
return dummyHead.next;
}
小结:
链表中使用指针来解题比较容易想到,但是也容易出错,所以在改变指针指向时应该细心一点,不要犯迷糊。
解法三:递归
- 找终止条件:本题终止条件很明显,当递归到链表为空或者链表只剩一个元素的时候,没得交换了,自然就终止了。
- 递归体:假设待交换的俩节点分别为head和next,next的应该接受上一级返回的子链表,就相当于是一个含三个节点的链表交换前两个节点。
- 找返回值:返回给上一层递归的值应该是已经交换完成后的子链表。
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null)
return head;
ListNode nextTemp = head.next;
head.next = swapPairs(nextTemp.next);
nextTemp.next = head;
return nextTemp;
}
假设链表为1->2->3->4->5,按照下图可有助理解!