题目:
输入一个链表,反转链表后,输出新链表的表头。
Reverse a singly linked list.
Example:
Input: 1->2->3->4->5->NULL
Output: 5->4->3->2->1->NULL
Follow up:
A linked list can be reversed either iteratively or recursively. Could you implement both?
2022.12.19
给想复杂了……还用了dummyHead,然后发现dummyHead一会儿成环了一会儿多了个0……才意识到根本不需要dummyHead……以及时隔两年,还是不会写递归……
2020.10.13 Java
差点没给写出来,吓得我以为我连反转链表都不会了。看了下自己新写的代码比以前的要简洁多了,有进步。对比了一下solutions居然除了变量名temp它起的是tempNext以外完全一毛一样,惊呆。
Runtime: 0 ms, faster than 100.00% of Java online submissions for Reverse Linked List.
Memory Usage: 38.7 MB, less than 6.72% of Java online submissions for Reverse Linked List.
/**
* 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) {
ListNode curr = head;
ListNode prev = null;
while (curr != null) {
ListNode temp = curr.next;
curr.next = prev;
prev = curr;
curr = temp;
}
return prev;
}
}
还是不会写递归,唉。知道了思路也在head.next.next=head那里卡住了。
Runtime: 0 ms, faster than 100.00% of Java online submissions for Reverse Linked List.
Memory Usage: 39.1 MB, less than 6.72% of Java online submissions for Reverse Linked List.
/**
* 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 || head.next == null) {
return head;
}
ListNode node = reverseList(head.next);
head.next.next = head;
head.next = null;
return node;
}
}
这道题没有什么特殊的技巧,就是普普通通地做就好了,也是一道非常经典的题,面试高频题。链表的题首先要考虑给出的头节点为空的情况,直接返回NULL。反转链表这个要格外注意不要把链表给断了,因此我们设置三个指针,分别指向当前节点curr、前一节点prev和后一节点next。在while循环中遍历整个链表,小心翼翼地将curr的next设为prev,并把prev和curr向后挪动一个,直到curr的next为空时达到了链表的尾部,把最后的curr设为反转链表的头节点:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
if (!pHead) {
return NULL;
}
ListNode* prev = NULL;
ListNode* curr = pHead;
ListNode* new_head = NULL;
while (curr) {
ListNode* next = curr->next;
if (!next) {
new_head = curr;
}
curr->next = prev;
prev = curr;
curr = next;
}
return new_head;
}
};
另外一种递归方法,我理解了好久才搞明白,其实还是比较难想的。首先递归基是当参数中的pHead为空或者pHead->next为空时,就返回pHead,作为反转链表的头节点。接下来通过递归调用这个函数,把递归返回的结果(其实仔细看会发现每次返回的都是原链表的最后一个节点,也就是新链表的头)存起来,然后把当前指向的节点的下一个节点的next设为它自己(这就把指针反过来了),再把当前节点的next设为空,方便下一次设置next(毕竟当前节点在下一次就是前面那句提到的“当前节点的下一节点了),最后返回的就是之前存起来的新链表的头。画了个图:
代码如下:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
if (!pHead || !pHead->next) {
return pHead;
}
ListNode* pReversedNode = ReverseList(pHead->next);
pHead->next->next = pHead;
pHead->next = NULL;
return pReversedNode;
}
};