プログラミング問題-チェーンテーブルとデュアルポインタ
まとめ:チェーンテーブルに関する問題の大部分はダブルポインタで解決できます.i.e.,チェーンテーブルの最後からk番目のノードを探し,チェーンテーブルの中間1/2ノードを探し,チェーンテーブルにリングがあるかどうかを検出する.スナップポインタ
1、チェーンテーブルの最後からk番目のノードを探す[1]
チェーンテーブルを入力し、チェーンテーブルの最後からk番目のノードを出力します.多くの人の習慣に合うように、本題は1から数え始めます.すなわち、チェーンテーブルの末尾ノードは最後から1番目のノードです.たとえば、チェーンテーブルには6つのノードがあり、先頭ノードから1、2、3、4、5、6の順に値が表示されます.このチェーンテーブルの最後から3番目のノードは4のノードです.
/*ダブルポインタ
1)p 1はp 2より先にk−1ステップ進み、p 1が最後のノードに達すると、p 2は最後からk番目のノードを指す
2)p 1はp 2より先にk歩進み、p 1が最終終点(NULL)に達すると、p 2は最後からk番目のノードを指す
*/
コード:
2、チェーンテーブルの中間ノード[2]
ヘッダノード
中間ノードが2つある場合は、2番目の中間ノードを返します.
考え方:高速ポインタ、高速ポインタp 2は一度に2歩、遅いポインタp 1は一度に1歩歩く.
特殊な処理が必要なのは、偶数ノードが2番目の中間ノードを出力することです.
3、リングチェーン[3]
チェーンテーブルにループがあるかどうかを判断し、ループがある場合は、ループの開始点を見つけます.
考え方:
1)リングがあるかどうかを確定して、速い遅いポインタ、速いポインタ*fastは毎回2歩(あるいは多歩)移動して、遅いポインタ*slowは毎回1歩移動して、もしリングが存在するならば、両者はきっとリングの上で出会って、しかも出会った時に遅いポインタはまだ1周を歩き終わっていません(leetcode公式の問題解を証明します);そうでなければリングがありません.
2)ループがあることを確認し(スナップポインタが出会った後)、そのうちの1つをチェーンテーブルの始点headに移動し、その後、両者は毎回1ステップ移動し、出会い点は入ループの始点となる.
c++コード
[1]https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/
[2]https://leetcode-cn.com/problems/middle-of-the-linked-list/
[3]https://leetcode-cn.com/problems/linked-list-cycle-ii/
1、チェーンテーブルの最後からk番目のノードを探す[1]
チェーンテーブルを入力し、チェーンテーブルの最後からk番目のノードを出力します.多くの人の習慣に合うように、本題は1から数え始めます.すなわち、チェーンテーブルの末尾ノードは最後から1番目のノードです.たとえば、チェーンテーブルには6つのノードがあり、先頭ノードから1、2、3、4、5、6の順に値が表示されます.このチェーンテーブルの最後から3番目のノードは4のノードです.
/*ダブルポインタ
1)p 1はp 2より先にk−1ステップ進み、p 1が最後のノードに達すると、p 2は最後からk番目のノードを指す
2)p 1はp 2より先にk歩進み、p 1が最終終点(NULL)に達すると、p 2は最後からk番目のノードを指す
*/
コード:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* getKthFromEnd(ListNode* head, int k) {
/*
p1 p2 k-1
*/
ListNode* p1 = head;
ListNode* p2 = head;
//p1 k-1
int step = 0;
while (stepnext;
}
if (!p1) return NULL;
while (p1->next)
{
p1 = p1->next;
p2 = p2->next;
}
return p2;
}
};
2、チェーンテーブルの中間ノード[2]
ヘッダノード
head
を有する非空の単一チェーンテーブルが与えられ、チェーンテーブルの中間ノードが戻される.中間ノードが2つある場合は、2番目の中間ノードを返します.
考え方:高速ポインタ、高速ポインタp 2は一度に2歩、遅いポインタp 1は一度に1歩歩く.
特殊な処理が必要なのは、偶数ノードが2番目の中間ノードを出力することです.
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* middleNode(ListNode* head) {
if (!head)
return head;
ListNode* p1 = head, *p2=head;
while (p2->next)
{
p1 = p1->next;
p2 = p2->next;
if (p2->next)
p2 = p2->next;
}
return p1;
}
};
3、リングチェーン[3]
チェーンテーブルにループがあるかどうかを判断し、ループがある場合は、ループの開始点を見つけます.
考え方:
1)リングがあるかどうかを確定して、速い遅いポインタ、速いポインタ*fastは毎回2歩(あるいは多歩)移動して、遅いポインタ*slowは毎回1歩移動して、もしリングが存在するならば、両者はきっとリングの上で出会って、しかも出会った時に遅いポインタはまだ1周を歩き終わっていません(leetcode公式の問題解を証明します);そうでなければリングがありません.
2)ループがあることを確認し(スナップポインタが出会った後)、そのうちの1つをチェーンテーブルの始点headに移動し、その後、両者は毎回1ステップ移動し、出会い点は入ループの始点となる.
c++コード
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if (!head)
return head;
ListNode *fast = head, *slow=head;
while (fast->next&&fast->next->next)
{
slow = slow->next;
fast = fast->next->next;
if (slow == fast) // ,
{
fast = head;
while (fast != slow)
{
fast = fast->next;
slow = slow->next;
}
return slow;
}
}
return NULL;
}
};
[1]https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/
[2]https://leetcode-cn.com/problems/middle-of-the-linked-list/
[3]https://leetcode-cn.com/problems/linked-list-cycle-ii/