当初の公開:
私は以前にU社の筆記試験でそのような問題に遭遇しました:
単一リンクリストにリングがあるかどうかを判別します。
最初にそのような常識を見てみましょう。実際のループと単一リンクリストのループの違いは何ですか?
明らかに:実際のループには、ループまたはエスケープの2つの方向があります。ただし、単一リンクリストでは、次のポインタは1つのポイントしか指すことができないため、循環リンクリストは永久に循環する必要があり、出口はありません。以下に示すように:
質問自体に戻って、単一リンクリストにリングがあるかどうかを判断する方法は?
アルゴリズム1:表記
考えるのが最も簡単なのは間違いなく表記です。リンクリストをトラバースするときは、訪問したノードを記録します。循環単一リンクリストの場合、繰り返しアクセスするノードが必要です。このような考え方はとても自然なことです。
マーキングするときは、スペースを消費するハッシュマップまたはハッシュセットの使用を検討できます。考え方が比較的明確なので、手順を詳しく紹介する必要はありません。
アルゴリズム2:ブルートフォースアルゴリズム
暴力は問題を解決する方法でもありますが、必ずしも最善の方法ではありません。
このように考えてみてください。黒まで行くと、最後まで到達するとリングがなくなり、最後まで到達しないと、リング内を回り続けることになります。
このトピックは、すべてのテストケースに合格できるブルートフォースメソッドを使用して、Leetcodeで実行しました。コードは次のとおりです。
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func hasCycle(head *ListNode) bool {
count := 0
max := 12000
for ; head != nil && count < max; {
count++
head = head.Next
}
if count == max {
return true
}
return false
}
一見すると、このブルートフォースアルゴリズムには制限があります。たとえば、リンクリストが十分に長い場合、カウントと最大値が等しくなり、誤判断につながる可能性があります。
アルゴリズム3:高速ポインタと低速ポインタ
二輪車が後ろにあり、前にあり、追いかけているのですが、道がない環状道路の場合、必然的に二輪車は自転車に追いつきます。
したがって、同様のアイデアを採用して、高速ポインターを背面に、低速ポインターを前面に配置して、単一リンクの時計にリングがあるかどうかを判断できます。この方法の利点は、スペースの複雑さがO(1)であり、誤判定がないことです。
アイデアがわかったので、プログラムを書くのは非常に簡単なことなので、繰り返しません。
良い週末を過ごして、来週あなたと話し、見て、または去ってください。