イベントアドレス: CSDN 21 日間学習チャレンジ
記事ディレクトリ
Leetcode21 - 2 つの順序付きリンク リストを結合する
トピックの説明
2 つの昇順リストを新しい昇順リストにマージして返します。新しいリンク リストは、指定された 2 つのリンク リストのすべてのノードを結合することによって形成されます。
例 1:
**入力: **l1 = [1,2,4]、l2 = [1,3,4]出力: [1,1,2,3,4,4]
例 2:
**入力:**l1 = [ ]、l2 = [ ]出力: [ ]
例 3:
**入力:**l1 = [ ]、l2 = [0]出力: [0]
ヒント:
- 2 つのリンクされたリストのノード数の範囲は [0, 50] です。
- -100 <= Node.val <= 100
- l1 と l2 は両方とも非降順です
コアコードパターン
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
}
アイデア分析とコード実装(C言語)
このアイデアは実際には非常に単純です。ここでは、センチネル ノードが新しいリンク リストのヘッド ノードとして使用され、2 つのポインタを使用して 2 つのリンク リスト内のノードを相互に比較します。小さい方が最初に挿入され、最後が新しいリンク リストに挿入されます。必ず最初にリンク リストが存在します。挿入後、まだ挿入されていないリンク リストが残りのノードを新しいリンク リストに一度に挿入します。注意点がいくつかあり、まずセンチネルノードを作成し、センチネルノードを指すガードポインタを定義しますが、このときセンチネルノードの次のポインタはすぐにNULLに初期化する必要があります。ワイルド ポインターの潜在的なリスクです。list1 リンク リストと list2 リンク リストにそれぞれ対応する 2 つのポインター cur1 と cur2 を定義します。while ループの条件は次のようになりますcur1&&cur2
。なぜですか? この場合、最初に挿入されたリンク リストがある限り、ループからすぐに抜け出します。ループが終了すると、どのリンク リストが挿入されなかったかに応じて、残りのすべてのノードが新しいリンク リストに末尾挿入されます。ここで使用する補助ノード - センチネル ノードはタイトルに指定されていません。最後に解放する必要がありますが、解放する前に、まずセンチネル ノードの次のポインタの内容を取り出して、それをヘッドポインタ。
コード
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2)
{
struct ListNode* cur1 = list1;
struct ListNode* cur2 = list2;
struct ListNode* guard = (struct ListNode*)malloc(sizeof(struct ListNode));
guard->next = NULL;
struct ListNode* tail = guard;
while(cur1 && cur2)
{
if(cur1->val > cur2->val)
{
tail->next = cur2;
tail = tail->next;
cur2 = cur2->next;
}
else
{
tail->next = cur1;
tail = tail->next;
cur1 = cur1->next;
}
}
if(cur1)
tail->next = cur1;
if(cur2)
tail->next = cur2;
struct ListNode* head = guard->next;
free(guard);
return head;
}
Leetcode206 - 逆リンクリスト
トピックの説明
単一リンク リストのヘッド ノード head を指定して、リンク リストを反転し、反転したリンク リストを返してください。
リンク:リートコード206
例
例 1:
**入力: **head = [1,2,3,4,5]出力: [5,4,3,2,1]
例 2:
**入力: **head = [1,2]出力: [2,1]
例 3:
**入力: **head = []出力: []
ヒント:
- リンクリストのノード数の範囲は[0, 5000]です。
- -5000 <= Node.val <= 5000
コアコードパターン
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* reverseList(struct ListNode* head)
{
}
アイデア分析とコード実装(C言語)
1. 新しいリンクリストの先頭挿入方法
実際、配列を使用する必要があることを除いて、この質問と基本的に同じ質問がありますが、ここでは単一リンク リストが使用されています。アイデアを参考にすることもできます。新しいリンク リストを作成することもできます。ただし、配列と比較すると、ここでは新しいノードを作成する必要はなく、ノード間のポインティング関係を変更する必要があります。新しいヘッド ポインター newHead を定義し、現在のノードを見つける cur ポインターを定義し、次のノードへの next ポインターを見つけます。cur が NULL を指さない限り、cur が指すノードを新しいリンク リストに追加します。それを置くには?newHead の内容を、ノードを指す cur の次のポインタに渡し、newHead が元々指していたものを指すようにします。次に、cur が指すノードのアドレスを newHead に渡し、newHead がノードを指すようにします。これらの操作を実行する前に、まず cur->next の値を next に入れ、実行後に next の値を cur に入れる必要があることに注意してください。実際には、元のノードを新しいリンク リストに前から後ろに 1 つずつ挿入することになります。
コード
struct ListNode* reverseList(struct ListNode* head)
{
struct ListNode* cur = head;
struct ListNode* newHead = NULL;
while(cur)
{
struct ListNode* next = cur->next;
cur->next = newHead;
newHead = cur;
cur = next;
}
return newHead;
}
2. 3ポインタ反転法
リンクリストはポインタで接続されているので、ポインタの指す関係を逆にすると、前のノード、現在のノード、次のノードをそれぞれ指す3つのポインタを使う方法を考えたことはありますか。ノード (prev、cur、next) の場合、cur のポイントが NULL でない限り、反転されていないノードがまだあるとみなされ、前のノードのアドレスが次のポインタに割り当てられます。 cur が指す現在のノードの値を変更して、前のノードを指すようにし、3 つのポインターを 1 ビット後方に移動し、cur が NULL を指すまでループを続けます。反転された新しいリンク リストの先頭ノードは prev で示されているので、prev に戻るだけです。
コード
struct ListNode* reverseList(struct ListNode* head)
{
struct ListNode* prev = NULL;
struct ListNode* cur = head;
struct ListNode* next = NULL;
while(cur)
{
next = cur->next;
cur->next = prev;
prev = cur;
cur = next;
}
return prev;
}