递归之24&206(链表)

24

Given a linked list, swap every two adjacent nodes and return its head.

You may not modify the values in the list's nodes, only nodes itself may be changed.

Example:

Given 1->2->3->4, you should return the list as 2->1->4->3.

206

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?


这里我们只考虑递归算法,24是从头开始,两两节点作交换。206是从头到尾逆序。(只考虑交换节点而非新建链表或交换节点值的实现)

我们上代码

24

 1 class Solution {
 2 public:
 3     ListNode* swapPairs(ListNode* head) {
 4         if (head==NULL || head->next==NULL)
 5             return head;
 6         ListNode *t = head->next;
 7         head->next = swapPairs(t->next);
 8         t->next = head;
 9         return t;
10     }
11 };

206

 1 class Solution {
 2 public:
 3     ListNode* reverseList(ListNode* head) {
 4         if (head == NULL || head->next == NULL) {
 5             return head;
 6         }
 7         ListNode* ret = reverseList(head->next);
 8         head->next->next = head;
 9         head->next = NULL;
10         return ret;
11     }
12 };

均以1->2->3->4链为例:

(格子里面的数字为对应代码段的首行代码号)

(*3 代表指向值为3的节点的指针)

(双箭头线为程序执行流)


考虑24的时候,可见三个节点-> 当前节点,当前节点指向的下一个节点,当前节点指向的下一个节点的下一个节点(递归返回)。

交换这三个节点的前两个节点即可,把递归返回节点视为已调整好的节点。(注意递归调用在代码段中央,这个中央是指节点指针域修改中)

而考虑206时,由于是要整个交换链表,那么宏观上就得有个概念,最终返回的是原链表最后一个节点的指针,所以执行时不断压入当前节点的下一个节点的指针,而返回的始终是“相对原链表的最后一个节点的指针”。(注意递归调用在代码段前,即在节点指针域修改前,因而能实现直接压到最后一个节点,而程序不断返回上一次递归的返回值,即从首次退栈<head=*4时首次退栈>到结束都是返回同一个指针)

递归执行中出现了某节点前后节点均指向自身的情况,前节点指向自身是前节点还未修改指针域,后节点指向自身是因为递归返回,上一次递归时“该节点的下一个节点”的指针域修改指向当前节点。递归结束后返回尾节点指针(现为头节点)


看程序和写程序是两码事,现在瞟一眼别人的指针个数和位置大概能明白和写出来。但是完全凭自己写还是太困难。

1.返回什么

2.干什么

3.什么时候退出

->4.递归调用位置。

每个人考虑问题的方式不同,造成每个选项可能都有异。从不同问题规模建模,每个选项干的事可能都不同,可能产生很多条路,但是通往正确的道路确实有限的。

原文地址:https://www.cnblogs.com/katachi/p/12562278.html