算法训练 第二周
二、反转链表
本题给我们了一个单链表的头节点head,要求我们把这个单链表的连接顺序进行逆置,并返回逆置后的链表头节点。
1.头插法
我们需要先创建一个新的头节点ph,然后遍历给出的单链表,把遍历到的每一个节点用头插法接到ph的后面,这样我们就可以得到一个反转后的链表了,最后返回ph的next即可。需要注意的是,在进行头插语句之前,我们需要把当前节点的下一个节点先存储起来,否则会导致遍历节点的next丢失,具体代码如下:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
if(head == null) {
return null;
}
ListNode ph = new ListNode();
ListNode p = head;
ListNode n;
while(p != null) {
n = p.next;
p.next = ph.next;
ph.next = p;
p = n;
}
return ph.next;
}
}
复杂度分析
- 时间复杂度:O(n),只需遍历一遍原链表即可。
- 空间复杂度:O(1)。
2.递归
递归法的要点在于我们需要先假设我们要处理的这个节点之前的节点已经全部完成反转,然后对于这个节点,我们只需要将它的next指向它的上一个节点即可,或者说我们需要将指针指向的节点的next的next指向这个节点本身,具体代码如下:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
if(head == null) {
return null;
}
if(head.next == null) {
return head;
}
ListNode prev = head.next;
ListNode p = prev.next;
head.next.next = head;
head.next = null;
return process(prev,p);
}
public ListNode process(ListNode prev,ListNode p) {
if(p == null) {
return prev;
}
if(p.next == null) {
p.next = prev;
return p;
}
ListNode ph = process(p,p.next);
p.next = prev;
return ph;
}
}
复杂度分析
- 时间复杂度:O(n),需要遍历整个链表。
- 空间复杂度:O(n),递归调用压栈的空间取决于原链表的长度。