リンクリストと再帰
リンクリスト要素の削除の問題への答え
問題の説明:リンクリスト[1、2、6、3、4、5、6]の値6の要素を削除します
-
ListNode.java
構造の説明public class ListNode { int val; ListNode next; ListNode(int x) { val = x;} /** * 链表节点构造函数,自定义 * @param arr */ ListNode(int[] arr) { if (arr == null || arr.length == 0) { throw new IllegalArgumentException("arr can not be empty"); } this.val = arr[0]; ListNode cur = this; for (int i = 1; i < arr.length; i++) { cur.next = new ListNode(arr[i]); cur = cur.next; } } @Override public String toString() { StringBuilder sb = new StringBuilder(); ListNode cur = this; while (cur != null) { sb.append(cur.val).append(" -> "); cur = cur.next; } sb.append("NULL"); return sb.toString(); } }
-
従来の方法では、リンクリストの3つの部分[ヘッド、ミドル、テール]は別々に処理されます
public ListNode removeElement(ListNode head, int val) { // 链表头部节点删除 while (head != null && head.val == val) head = head.next; // 链表尾部节点删除 if (head == null) { return null; } // 链表中间部分节点删除 ListNode prev = head; while (prev.next != null) { if (prev.next.val == val) prev.next = prev.next.next; else prev = prev.next; } return head; } }
-
仮想ヘッドノード方式では、各リンクリストノードにプレノードが含まれるようになり、コードが改善されます。
public ListNode removeElement(ListNode head, int val) { // 建立虚拟头结点,保证链表中每一个节点前面均有节点 ListNode dummyHead = new ListNode(-1); dummyHead.next = head; // 链表节点删除 ListNode prev = dummyHead; while (prev.next != null) { if (prev.next.val == val) prev.next = prev.next.next; else prev = prev.next; } return dummyHead.next; }
-
テストしてください!
public static void main(String[] args) { int[] arr = { 1, 2, 6, 3, 4, 5, 6}; ListNode res = new ListNode(arr); System.out.println(res); new Solution2().removeElement(res, 6); System.out.println(res); } ------------------------------------------ 1 -> 2 -> 6 -> 3 -> 4 -> 5 -> 6 -> NULL 1 -> 2 -> 3 -> 4 -> 5 -> NULL
再帰:コンピューターの非常に重要なコンポーネントロジックメカニズム
-
基本的に、元の問題は、配列の合計など、より小さな同じ問題に変換されます。
SUM(arr[0...n-1]) = arr[0] + SUM(arr[1...n-1])
SUM(arr[1...n-1]) = arr[1] + SUM(arr[2...n-1])
SUM(arr[n-1...n-1]) = arr[n-1] + SUM(arr[]) = arr[n-1] + 0
-
再帰的アルゴリズムの構成
求解最基本的问题
把原问题转化成更小的问题
-
リンクリストは再帰的です
- リンクリストは、複数のノードの接続本体として理解でき、接続本体と見なすこともでき
一个节点和一个链表
ます。 - これは
NULL
、最も基本的なリンクリストでもあります。 - わかりやすくするために絵を描きました!
- 写真によると、コードを書き直すことができます!
public ListNode removeElementNew(ListNode head, int val) { // 基础问题 one if (head == null) { return null; } // 处理子链表,分解问题 two head.next = removeElementNew(head.next, val); // 处理结果,若当前返回子链表满足条件,便跳过节点 three return head.val == val ? head.next : head; }
- たとえば、リンクリスト
1, 2, 3
があり、要素を削除したいのです2
が、上記の方法はどのように実行されますか?step1
ヘッドノードとして1を使用して[1、2、3]リンクリストを入力しますone
ヘッド!= nulltwo
head.next =?、最初の再帰を入力し、step2
step2
ヘッドノードとして2を使用して[2、3]リンクリストを入力しますone
ヘッド!= nulltwo
head.next =?、 2番目の再帰を入力します。step3
step3
エントリ[3]ヘッドノードとして3を使用したリンクリストone
ヘッド!= nulltwo
head.next =?、 3番目の再帰を入力します。step4
step4
入力パラメータ[NULL]、NULLリンクリストone
head == null、returnnull
、基本的な問題が発生しました!!!
step5
戻るstep3 two
two
head.next =【null】three
head.val == 2?head.next:頭- ヘッドを返す、リンクリストは[3]になり、リターン
step2 two
step6
戻るstep2 two
two
head.next =【3】three
head.val == 2?head.next:head、此时条件满足,为true
- head.nextを返します。リンクリストは[3]になり、return
step1 two
step7
戻るstep1 two
two
head.next =【3】three
head.val == 2?head.next:頭- ヘッド戻り、リスト[1、3]であり、この時間は、バック
step1
、引き継がれたone
、、two
、three
メソッド戻り、終了します。
- リンクリストは、複数のノードの接続本体として理解でき、接続本体と見なすこともでき
-
再帰呼び出しにはコストがかかります:関数呼び出し+システムスタックスペース(現在の実行位置、変数ステータス、および時間消費を記録します)。基本的な問題が処理されない場合、つまり再帰出口がない場合、メソッドの実行は次のようになります。メモリがいっぱいになるかオーバーフローするまでメモリを占有し、システムをオーバーさせます。アルゴリズムは常に限られた回数の実行後に終了する必要があり、各ステップは限られた時間で完了することができます。