class Solution
{
public:
void hanota(vector<int>& A, vector<int>& B, vector<int>& C)
{
dfs(A, B, C, A.size());
}
void dfs(vector<int>&A, vector<int>& B, vector<int>& C, int n)
{
// 出口条件
if(n == 1)
{
C.push_back(A.back());
A.pop_back();
return;
}
// n > 1时候
// 1、A上的n-1个盘子通过C到B
dfs(A, C, B, n - 1);
// 2、A盘子push给C盘子
C.push_back(A.back());
A.pop_back();
// 3、B上的n-1个盘子通过A到C
dfs(B, A, C, n - 1);
}
};
我们最关键的在于我们要用宏观的角度去看问题,这个汉诺塔问题其实不难,思路来讲很简单,但我们需要明确的是为什么能够用到递归?为什么递归那么好用?其用处在哪?
我们一一来进行解答:我们模拟一下这个形式。
发现了,这子问题和上面的问题一模一样,每一个子问题之间都是一样的,那么我们就可以用递归来进行解决,只要能够重复子问题,用这个函数头来进行解决的都是用递归来进行解决。
我们继续去解决一个问题,我们从上面这个图上面得到了什么,我们从A柱子上面的n-1个盘子放到B上面,再将B上面的n-1个盘子放到A上,发现了吗?我们都是整个盘子移动的,是整体移动的!
所以我们从宏观上面来讲:
那我们再模拟一下递归展开图(其中的细节为什么是back()而不是[0]?):
leetcode链接
class Solution
{
public:
ListNode* mergeTwoLists(ListNode* list1, ListNode* list2)
{
// 1、先写出口
if(list1 == nullptr)
return list2;
if(list2 == nullptr)
return list1;
// 2、函数体
if(list1->val <= list2->val)
{
list1->next = mergeTwoLists(list1->next, list2);
return list1;
}
else
{
list2->next = mergeTwoLists(list1, list2->next);
return list2;
}
}
};
我们依旧考虑子问题的解决,我们发现其大问题和子问题都是一样的,我们下面来模拟一下:
class Solution
{
public:
ListNode* reverseList(ListNode* head)
{
// 出口 -- 叶子结点或者head本身就是0
if(head == nullptr || head->next == nullptr)
{
return head;
}
// 进行递归dfs到最后一个叶子结点(深度优先遍历)
ListNode* newhead = reverseList(head->next);
// 逆置 -- 这里是执行上一层的head
head->next->next = head;
head->next = nullptr;
return newhead;
}
};
class Solution
{
public:
ListNode* swapPairs(ListNode* head)
{
// 出口
if(head == nullptr || head->next == nullptr)
return head;
// 函数体
ListNode* tmp = swapPairs(head->next->next);
ListNode* Ret = head->next;
Ret->next = head;
head->next = tmp;
return Ret;
}
};
class Solution
{
public:
double myPow(double x, int n)
{
return n < 0 ? 1.0 / pow(x, -(long long)n) : pow(x, n);
}
double pow(double x, long long n)
{
if(n == 0)
{
return 1.0;
}
double tmp = pow(x, n / 2);
return n % 2 == 0 ? tmp * tmp : tmp * tmp * x;
}
};