1. アイデア
K が 2 であるとします。下の図によると、下から K 番目のノードが 45 であることがわかります。
K を見つけてこのノードを返すには、K がリンク リストの範囲内にあることを確認する必要があるため、K は負の値や 0 にすることはできず、リンク リスト内のノードの数を超えることはできないという前提に注意してください。このノードが見つからない場合、それを返すことは不可能です。
すべてのノードを走査した後でのみ、下から K 番目のノードを見つけることができるため、ループを使用してノードを 1 つずつ走査することが必ず必要です。
次に、現在のノードがターゲット ノードであるかどうかを判断し、ターゲット ノードである場合はループから抜け出してこのノードに戻り、そうでない場合はリンク リストが完全に探索されるまで次のノードを探し続けます。
次に理解する必要があるのは、ループの終了条件、つまり現在のノードがターゲット ノードであるかどうかをどのように判断するかです。
まず、高速と低速の 2 つのポインターを定義できます。どちらも最初のヘッド ノードの位置を指しますが、最初に高速が K-1 ステップを実行するようにします。
どのノードが指すかは K によって異なります。K が負の数または 0 である場合、またはリンク リスト内のノードの数を超えている場合、
fast によって指す位置は明らかに不正です。
K が 0 の場合、fast は 0-1 の位置に移動しますが、これは現時点では明らかに不正です。
K が -1 の場合、fast は -1-1 の位置に移動しますが、これは現時点では明らかに不正です。
K の値がリンク リスト内のノードの数を超えると、高速性は最終的にリンク リストを超えます。
上記の 3 つの違法な状況は、明らかに私には使用できません。
したがって、コードの最初で、現在の K が正当であるかどうかを判断する必要があり、正当である場合は次のステップに進み、正当でない場合は、K の現在の値に問題があることを示すために null を直接返します
。
K-1 ステップの高速歩行の後、2 つのノードをステップごとに歩行させます。最初に高速歩行が行われるため、確実にゆっくりと歩くよりも多く歩くことになります。fast の次のノードが空の場合、slow は下から K 番目のノードを指します。この時点でループは終了なので、飛び出した後はスローに戻るだけです。
K の値が 1 の場合、fast は K-1 ステップを実行します。つまり 1 ステップも移動せず、2 つのポインターはヘッド ノードの位置で一緒に移動を開始します。
fast の次のノードが空の場合、slow は正確に最後の 1 (K の値) ノードを指していることがわかります。
この考え方は奇数ノードと偶数ノードの影響を受けず、この方法はリンク リスト ノードが奇数か偶数かに関係なく適用できます。
fast が K-1 ステップを完了すると、slow よりも常に 1 つ多くのステップが必要となるため、fast の次のノードが空の場合、slow は、最後から 2 番目のノード (K の値) である fast の前のノードを指します。
2. 詳細な処理
1. まず、K の値が正しいかどうかを判断し、正しくない場合は直接 null を返します。
//k位置不合法
if (k <= 0 || this.head == null) {
return null;
}
2. 2 つのポインタを定義し、1 つはfast、もう 1 つはlowと呼ばれ、両方ともヘッド ノードを指すようにします。
//定义一个fast和slow指向head
ListNode fast = this.head;
ListNode slow = this.head;
3. 最初に K -1 歩を速く進めましょう。
while (k - 1 != 0) {
fast = fast.next;
if (fast == null) {
return null;
}
k--;
}
このときの K の値が 2 であれば、fast が先に 1 歩進みますが、現在の K の値が 1 であれば、fast は 1 歩進みません。
上記サイクルは直接入りません。
K の値が 2 の場合、fast は最初に 2 番目のノードの位置に移動します。
4. 2 つのポインタを同時に動かします。
//然后两个一起走
//当fast.next==null的时候,slow所指的位置就是倒数第k个结点
while (fast.next != null) {
//两个一起走
fast = fast.next;
slow = slow.next;
}
return slow;//此时slow指向的就是倒数第k个结点
最後から2番目のノードは、この時点でslowが指すノードである。
完全なコード
public ListNode findKthToTail(int k) {
//k位置不合法
if (k <= 0 || this.head == null) {
return null;
}
//定义一个fast和slow指向head
ListNode fast = this.head;
ListNode slow = this.head;
//先让fast走k-1步
while (k - 1 != 0) {
fast = fast.next;
if (fast == null) {
return null;
}
k--;
}
//然后两个一起走
//当fast.next==null的时候,slow所指的位置就是倒数第k个结点
while (fast.next != null) {
//两个一起走
fast = fast.next;
slow = slow.next;
}
return slow;//此时slow指向的就是倒数第k个结点
}
この時点でニウケのテストは合格したことがわかります。
\