目次
2. 指定された値 x に基づいてリンク リストを 2 つの部分に分割し、x 未満のすべてのノードを x 以上のノードの前に配置するコードを作成します。
4. 2 つのリンク リストを入力し、最初の共通ノードを見つけます。
5. リンクリストが与えられた場合、そのリンクリストにリングがあるかどうかを判断します。
6. リンク リストが与えられた場合、リングへの参加を開始するリンク リストの最初のノードを返します。リンクされたリストが非巡回の場合は NULL を返します
横たわらずに輝いてください!
1. 2 つのソート済みリンク リストを新しいソート済みリンク リストにマージし、戻ります。新しいリンク リストは、指定された 2 つのリンク リストのすべてのノードを結合することによって形成されます。
https://leetcode.cn/problems/merge-two-sorted-lists/
コード 1 は次を示します: (ヘッダーなし)
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
if (list1 == NULL)
{
return list2;
}
if (list2 == NULL)
{
return list1;
}
struct ListNode* head = NULL;
struct ListNode* tail = NULL;
while (list1 && list2)
{
struct ListNode* next1 = list1->next;
struct ListNode* next2 = list2->next;
if ((list1->val) < (list2->val))
{
if (tail == NULL)
{
head = list1;
tail = list1;
}
else
{
tail->next = list1;
tail = list1;
}
list1 = next1;
}
else
{
if (tail == NULL)
{
head = list2;
tail = list2;
}
else
{
tail->next = list2;
tail = list2;
}
list2 = next2;
}
}
if (list1 != NULL)
{
tail->next = list1;
}
if (list2 != NULL)
{
tail->next = list2;
}
return head;
}
アイデア: 毎回小さなノードを取得し、それを新しいノードに挿入します。
注:どちらかが空の場合は注意してください
見出し付き単一リンクリスト: head->next は最初のノードのアドレスを参照します (先頭、先頭の追加ノードに相当しますが、ノード内の val は不確実で、next は次のノードを指します)。 -linked list: head 最初のノードのアドレスを参照します。デフォルトでは、OJ の質問は主導権を持ちません。
コード 2 は次のように示します: (主導権を握る)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
struct ListNode* head = (struct ListNode*)malloc(sizeof(struct ListNode));//创建一个头
struct ListNode* tail = head;
head->next = NULL;//就是含有值的节点的第一个
while (list1 && list2)
{
struct ListNode* next1 = list1->next;
struct ListNode* next2 = list2->next;
if ((list1->val) < (list2->val))
{
tail->next = list1;
tail = list1;
list1 = next1;
}
else
{
tail->next = list2;
tail = list2;
list2 = next2;
}
}
if (list1 != NULL)
{
tail->next = list1;
}
if (list2 != NULL)
{
tail->next = list2;
}
struct ListNode* list = head->next;
free(head);
return list;
}
アイデア: 毎回小さなノードを取得し、それを新しいノードに挿入します。
注: malloc のアドレスは最後に解放する必要があります。
2.指定された値xに基づいてリンク リストを 2 つの部分に分割し、 x未満のすべてのノードをx以上のノードの前に配置するコードを作成します。
コード表示:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class Partition {
public:
ListNode* partition(ListNode* pHead, int x) {
// write code here
struct ListNode* LessHead = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* LessTail = LessHead;
struct ListNode* GreaterHead = (struct ListNode*)malloc(sizeof(struct ListNode));
struct ListNode* GreaterTail = GreaterHead;
struct ListNode* cur = pHead;
while (cur != NULL)
{
if (cur->val < x)
{
LessTail->next = cur;
LessTail = cur;
}
else
{
GreaterTail->next = cur;
GreaterTail = cur;
}
cur = cur->next;
}
GreaterTail->next = NULL;
LessTail->next = GreaterHead->next;
struct ListNode* list = LessHead->next;
free(LessHead);
free(GreaterHead);
return list;
}
};
アイデア: x 未満をリンク リストに挿入、x 以上をリンク リストに挿入、リンク リスト 1 とリンク リスト 2 をマージ (先頭のものを使用)
注: リンク リスト 2 の最後の項目は NULL を指している必要があります。NULL を指していない場合、無限ループが発生する可能性があります [リンク リストの質問では、先頭と末尾に注意してください]
3. 連結リストの回文構造
コード表示:
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* cur = head;
struct ListNode* prev = NULL;
while(cur)
{
struct ListNode* next = cur->next;
cur ->next = prev;
prev = cur;
cur = next;
}
return prev;
}
struct ListNode* middleNode(struct ListNode* head)
{
struct ListNode* slow = head;
struct ListNode* fast = head;
while (fast && (fast ->next))
{
slow = slow ->next;
fast = fast->next->next;
}
return slow;
}
class PalindromeList {
public:
bool chkPalindrome(ListNode* A) {
// write code here
struct ListNode* mid = middleNode(A);
struct ListNode* rHead = reverseList(mid);
while (A && rHead)
{
if (A->val == rHead->val)
{
A = A->next;
rHead = rHead->next;
}
else
{
return false;
}
}
return true;
}
};
アイデア: まず、リンク リストの中間アドレス (奇数) または 2 番目のリンク リストの先頭として 2 番目の中間アドレス (偶数) を見つけます。次に、2 番目のリンク リストを反転し、次に元のリンク リストと 2 番目のリンク リストを反転します。リストを比較します。(元のリンク リストと 2 番目のリンク リストのいずれかが空の場合、ループから抜け出すことができ、それが回文リンク リストであることを示します)
4. 2 つのリンク リストを入力し、最初の共通ノードを見つけます。
https://leetcode.cn/problems/intersection-of-two-linked-lists/description/
コード表示:(案2)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB)
{
//判断是否相交
struct ListNode* tailA = headA;
struct ListNode* tailB = headB;
int lenA = 1;
int lenB = 1;
while (tailA->next != NULL)
{
tailA = tailA->next;
lenA++;
}
while (tailB->next != NULL)
{
tailB = tailB->next;
lenB++;
}
if (tailA != tailB)
{
return NULL;
}
//找到节点
int gap = abs(lenA - lenB);
//想法值得学习,大小
struct ListNode* shortList = headA;
struct ListNode* longList = headB;
if (lenA > lenB)
{
shortList = headB;
longList = headA;
}
while(gap--)
{
longList = longList->next;
}
while (longList && shortList)
{
if (longList == shortList)
{
return longList;
}
longList = longList->next;
shortList = shortList->next;
}
return NULL;
}
アイデア 1 : A リンク リストと B リンク リストの各ノードを順番に比較し、等しい場合はそれが交点であり、最初の等しいものが交点になります。
(交差点かどうか、交差点の数を判定) 時間計算量:O(M*N)
アイデア 2 : 末尾ノードのアドレスが同じ場合、交差です。(交差点かどうかの判断)
2 つのリンク リストの長さを調べて、リンク リストの方が長い場合は最初に 2 つのリンク リスト間の差をたどり、次に 2 つのリンク リストを一緒にたどります。アドレスが同じ場合、その位置はノードです (何は交点) 時間計算量: O(M+ N)
注: (1) アドレスは同じですが、値が等しいわけではありません(値はノードと必ずしも等しいとは限りません)
(2) コンパイラが実行する内容は文法エラーであり、コンパイラは実行ロジックをチェックアウトできないため、最後に return NULL を追加する必要があります (上に if があり値を返すため、コンパイラはif 条件が満たされない場合、戻り値はありません)。
5. リンクリストが与えられた場合、そのリンクリストにリングがあるかどうかを判断します。
https://leetcode.cn/problems/linked-list-cycle/submissions/
コード表示:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head)
{
struct ListNode* slow = head;
struct ListNode* fast = head;
while (fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)
{
return true;
}
}
return false;
}
アイデア: [ファストとスロー ポインタ] スローは一度に 1 歩ずつ進み、ファストは一度に 2 歩ずつ進み、スローがリングに入るとキャッチアップ モードがオンになり、最後にファストがスローに追いつきます。リングはありません。 fast->next または fast は NULL になります。リングがある場合は NULL になりません。
注: 最初は、高速と低速は等しいため、ループ内では、最初に割り当ててから比較します。
(1)遅い場合は1歩ずつ、速い場合は2歩ずつ進めば追いつきます。
スローが半分まで進むと、ファストがリングに入り始めます。この時の二人の距離はNで、1回ごとに距離が1ずつ減っていくので必ず追いつくことができます。【距離は0、追いつく】
(2) 遅い場合は 1 歩ずつ、速い場合は 3 歩ずつ進み、追いつけない場合があります。
スローが1/3になると、ファストがリングに入り始めます。このときの二人の距離はNです。1回ごとに距離は2ずつ減っていきます。距離が奇数の場合は見逃します。【偶数なら追いつきます】。このとき、距離はリング番号-1【偶数は追いつく、奇数は追いつく】決して追いつけない】ので、追いつけない可能性があります。
6. リンク リストが与えられた場合、リングへの参加を開始するリンク リストの最初のノードを返します。リンクされたリストが非巡回の場合は NULLを返します
https://leetcode.cn/problems/linked-list-cycle-ii/description/
コード表示:(案1)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *detectCycle(struct ListNode *head)
{
struct ListNode* fast = head;
struct ListNode* slow = head;
while (fast && fast->next)
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)
{
struct ListNode* meet = slow;
while (head != meet)
{
meet = meet->next;
head = head->next;
}
return meet;
}
}
return NULL;
}
アイデア1:リングに入るまでの距離をL、リングに入ってから二人が出会うまでの遅い移動距離×距離、リングに入ってからの二人の距離をN、リングの長さをCとする(速いと遅い)ポインター] ゆっくりは 1 歩歩きます、速いは一度に 2 歩かかります、速いは遅いの 2 倍の速さです [遅い場合は円を一周歩くことはなく、速い人に追いつかれますが、円を歩かずに速い人に追いつきます。スローがリングに入り、二人の距離は N で、N はリングの数より小さくなければなりません。したがって、二人が出会ったとき、スローは一周してはいけません。したがって、スローが移動した距離はリングに入るまでの距離です。 + 二人が出会う前とリングに入った後の距離 x は L+x; 高速で移動した距離は nC+L+x; n*C+L+x=2(L+x),----n *C=L+x; n は未知数]【遅い リングに入ったら速い人は一周するのは不可能】 n*C=L+x: エントリーリストから歩いていることが証明できる、もう1人は合流点から歩き、リングの入り口でゆっくりと速く合流します。
アイデア 2 : リンク リストの交点を見つけるように変換します。[合流点からの切断] 尾部として合流、合流→次を先頭として、先頭が与えられ、交点を見つけます。
7. リンク リストが与えられると、各ノードには追加のランダム ポインタが含まれ、リンク リスト内の任意のノードまたは空のノードを指すことができます。このリンクされたリストのディープ コピーを返すリクエスト
https://leetcode.cn/problems/copy-list-with-random-pointer/description/
コード表示:
/**
* Definition for a Node.
* struct Node {
* int val;
* struct Node *next;
* struct Node *random;
* };
*/
struct Node* copyRandomList(struct Node* head)
{
struct Node* cur = head;
//拷贝节点链接
while (cur!= NULL)
{
struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
copy->val = cur->val;
copy->next = cur->next;
cur->next = copy;
cur = cur->next->next;
}
//random
cur = head;
while (cur != NULL)
{
if (cur->random == NULL)
{
cur->next->random = NULL;
}
else
{
cur->next->random = cur->random->next;
}
cur = cur->next->next;
}
//摘下来、链接
struct Node* copyHead = NULL;
struct Node* copyTail = NULL;
cur = head;
while (cur != NULL)
{
struct Node* copy = cur->next;
struct Node* next = copy->next;
if (copyHead == NULL)
{
copyHead = copyTail = copy;
}
else
{
copyTail->next = copy;
copyTail = copy;
}
cur = next;
}
return copyHead;
}
アイデア: 各ノードをコピーして元のノードに接続し、コピーしたノードのランダムをリンクします。新しいランダムは前のランダムの隣にあります。最後に、コピーしたノードをほどいてリンクします。[インデックスは0から始まります]
その他の質問のリンクリスト
リートコード: https://leetcode.cn/tag/linked-list/problemset/
Niuke.com: https://www.nowcoder.com/exam/oj