花式反转单链表
1. 用反转数组的思路:反转[1:] 然后把head 怼在后面。与数组不同“怼在后面” 这个操作是O(n) 效率很差。
ListNode* reverseList(ListNode* head) { if (!head) return nullptr; if (!head->next) return head; ListNode* c = reverseList(head->next); ListNode* p = c; while (p->next) { p = p->next; } p->next = head; head->next = nullptr; return c; }
2. 改进上面的方法,优化掉后面那个O(n) 的添加操作。方法是:记住已反转好的tail,这样只用tail->next = head 就可以了,不需要遍历整个链表。
ListNode* re(ListNode* head, ListNode** tail) { if (!head) return nullptr; if (!head->next) { *tail = head; return head; } ListNode* t{nullptr}; ListNode* c = re(head->next, &t); t->next = head; head->next = nullptr; *tail = head; return c; } ListNode* reverseList(ListNode* head) { ListNode* t; return re(head, &t); }
3. 三指针。思路是从最普通的设想改进而来:
设想要反转 1->2->3->4->NULL
如果可以做到这样就好了:1<-2->3->4->NULL
比如现有指针p 指在2 上,现在只用把p 往前挪, 然后让p 指向2 就可以了。但是这个显然没法做到,因为这是一个单链表,不可能同时指向前和后。
那就想办法同时保存前后指针。
假设现在有两个链表:
1<-2<-r h->3->4->NULL
r, h 分别指向两个链表的头部,则执行以下操作:
t = h;
h = h->next;
t->next = r;
r = t;
得到以下两个链表
1<-2<-3<-r h->4->NULL
重复以上步骤,知道h 为NULL 时停止,则r 就指向反转后的链表。
ListNode* reverseList(ListNode* head) { if (!head) return nullptr; ListNode* re = head; head = head->next; re->next = nullptr; while (head) { ListNode* t = head; head = head->next; t->next = re; re = t; } return re; }