文章鏈接:https://leetcode-cn.com/explore/orignial/card/recursion-i/256/principle-of-recursion/1200/
遞歸函數
對於一個問題,如果存在遞歸解決方案,我們可以按照以下步驟來實施它。
舉個例子,我們將問題定義爲有待實現的函數 {F(X)}F(X),其中 {X}X 是函數的輸入,同時也定義了問題的範圍。
然後,在函數 {F(X)}F(X) 中,我們將會:
- 將問題逐步分解成較小的範圍,例如 {x_0} \in Xx0∈X, {x_1} \in Xx1∈X, ..., {x_n} \in Xxn∈X;
- 調用函數 {F(x_0)}F(x0), F(x_1)F(x1), ..., F(x_n)F(xn) 遞歸地 解決 {X}X 的這些子問題;
- 最後,處理調用遞歸函數得到的結果來解決對應 {X}X 的問題。
示例
爲了進一步展示上述步驟,我們再舉一個例子來說明如何遞歸地解決問題。
給定鏈表,交換每兩個相鄰節點並返回其頭節點。
例如,對於列表 1-> 2 -> 3 -> 4,我們應當返回新列表 2 -> 1 -> 4 -> 3 的頭節點。
我們可以定義函數 swap(head)
以實現解決方案,其中輸入的參數 head
指向鏈表的頭節點。而該函數應當返回將鏈表中每兩個相鄰節點交換後得到的新列表的頭節點 head
。
按照我們上面列出的步驟,我們可以按下面的流程來實現函數:
- 首先,我們交換列表中的前兩個節點,也就是
head
和head.next
; - 然後我們以
swap(head.next.next)
的形式調用函數自身,以交換頭兩個節點之後列表的其餘部分。 - 最後,我們將步驟(2)中的子列表的返回頭與步驟(1)中交換的兩個節點相連,以形成新的鏈表。
練習
給定一個鏈表,兩兩交換其中相鄰的節點,並返回交換後的鏈表。
你不能只是單純的改變節點內部的值,而是需要實際的進行節點交換。
示例:
給定1->2->3->4
你應該返回2->1->4->3
這裏我自己考慮的是:
鏈表的個數不管多長 只有奇數和偶數。
並且只要判定最後一輪 能夠正常交換鏈表的數據就可以。
只要最後一輪是正常可以更換,那麼遞歸到前面也是正常的。
判斷的控制條件就是在於: 長度爲奇數的時候最後一個node是無法交換的,那麼得從倒數第二個開始。這樣就可以正常交換了。
如果是偶數長度,那就不影響交換。
自己畫了一個草圖
比如
上面是偶數的鏈表 從遞歸開始後到達3,因爲是最後兩個都有數據,所以可以兩兩替換
下面的是奇數的鏈表,從遞歸開始後到3,因爲最後一個是奇數 他下一位是null,所以它就沒有可以替換的數字,就放棄掉。改從倒數第二位和第三位開始替換。
所以整個代碼如下:
//鏈表類
class ListNode {
int val;
ListNode next;
ListNode(int x) { val = x; }
}
class Solution {
public ListNode swapPairs(ListNode head) {
//head == null 是保證遞歸到最後一個是偶數列表個數
//head.next == null 是保證遞歸到最後一個是奇數列表個數
if (head == null || head.next == null){
return head;
}
swapPairs(head.next.next); //返回的是null的話 就從最後一個有效的開始對換
//第一個和後面一個替換
int tmp = head.val;
head.val = head.next.val;
head.next.val = tmp;
//如果是鏈表個數爲奇數的話 有一個不能替換。
return head;
}
}
提交記錄如下: