blog

LeetCode 86|連鎖表の基本、連鎖表の全要素を一度に反復処理する

今日はLeetCodeのトピックで、LeetCodeの問題86のパーティションリストと一緒です。\n\n問題の意味\nまず第一に、質問の意味を見てみましょう。質問の意味は、チェーンテーブルと整数xが与...

Jul 24, 2020 · 3 min. read
シェア


LeetCodeのトピックに関する53回目の記事は、LeetCodeの問題86「パーティションリスト」です。

トピックの意味

まず問題を見てみましょう。リンクされたテーブルと整数xが与えられたとき、リンクされたテーブルの前半の結果がxより小さく、リンクされたテーブルの後半の結果がx以上となるように、xに従ってリンクされたテーブルの要素をマージすることが要求されています。

サンプルをご覧ください:

Input: head = 1->4->3->2->5->2, x = 3
Output: 1->2->2->4->3->5

3によれば、連鎖表の元素を3未満のものと3以上のものに分けることができ、そのうち122が3未満、435が3以上です。その結果、122と435からなる新しい連鎖表ができ、122と435の元素の相互の順序は変わりません。

問題解決

リンクされたテーブルとその要素をどのように扱うかについて制限はないので、テーブルとそのデータを好きなように操作することができます。 最も単純な方法は、リンクされたテーブルの要素をxに基づいて2つに分割し、それらを2つの別々のリンクされたテーブルに入れ、2つのリンクされたテーブルをマージすることだと考えるのは簡単です。マージも非常に簡単で、リンクリストを結合するだけです。

連鎖したテーブルをたどり、それぞれに別の連鎖したテーブルを挿入し、最後に2つを1つに統合すれば完了です。

コードを書くのは簡単です:

# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
 def partition(self, head: ListNode, x: int) -> ListNode:
 # 2つのリンクされたテーブルを作成する
 left = ListNode(0)
 right = ListNode(0)
 # そして、2つのリンクされたテーブルをトラバースするために使用されるポインタ
 ln = left
 rn = right
 pnt = head
 while pnt is not None:
 # x未満は左に挿入し、それ以外は右に挿入する
 if pnt.val < x:
 ln.next = ListNode(pnt.val)
 ln = ln.next
 else:
 rn.next = ListNode(pnt.val)
 rn = rn.next
 pnt = pnt.next
 
 # 左右を組み合わせる
 ln.next = right.next
 return left.next

これは確かに可能ですが、元の連鎖表を破棄することで余分なスペースを空けることになります。新しいリンク・テーブルを作成せずに、この問題を解決したい場合はどうすればよいでしょうか?

連鎖表を走査し、x以上の要素を見つけたら連鎖表の末尾に移動させるだけです。こうして探索が終わると、連鎖表の操作は完了です。この考え方は単純ですが、時間の実装には多くの落とし穴があり、特に注意が必要です。

例えば、トラバーサル中にいくつかの要素がチェーンテーブルの末尾に移動する可能性があるため、トラバーサルのフォーカスを記録するための値が必要です。そのため、Noneを終点として使用することはできません。x以上の最初の要素を終点として使用し、探索がこの位置に達したときに終了する必要があります。チェインテーブルの操作については、他にも多くの詳細がありますので、コードを見に来てください:

# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
 def partition(self, head: ListNode, x: int) -> ListNode:
 tail = head
 if head is None:
 return None
 
 # x以上の要素が端の後ろに配置されていることを見つけるとき、終わりを見つける
 while tail.next is not None:
 tail = tail.next
 
 # トラバーサルの終了を記録する
 end_point = None
 
 pnt = ListNode(0)
 pnt.next = head
 head = pnt
 while pnt.next is not end_point:
 cur = pnt.next
 if cur.val >= x:
 # 最後に挿入する
 tail.next = cur
 tail = cur
 # エンドポイントがNoneの場合に更新する
 # end_pointそれは一度だけ更新される
 if end_point is None:
 end_point = cur
 pnt.next = cur.next
 continue
 pnt = pnt.next
 tail.next = None
 return head.next

まとめ

この問題では、リンクされたテーブルを操作し、そこからいくつかの要素を抽出して末尾に置くことが問題です。条件を満たすために新しいリンクテーブルを作成しても、元のリンクテーブルを変更しても、アルゴリズムの複雑さは同じですが、空間の複雑さが異なるため、コーディングの複雑さも異なります。相対的に言えば、最初の方法はより単純で、2番目の方法はやや複雑ですが、連鎖表の基本的な操作に慣れていれば、決して難しいものではありません。

チェーンテーブルに関連する問題については、多くのことを行っている必要がありますが、今日のトピックは非常に基本的であると考えられている、私は我々が問題を持っている必要がないと信じて、私は繰り返しません。

Read next

イテレーターについて

イテレータは、コンテナをトラバースするために使用され、イテレータパターンは、2つの責任がより単一であるように、イテレータクラスに分割された操作のコレクションのトラバーサルからオブジェクトのコレクションになり、その結合を低減します。トラバーサル用の連鎖配列の場合は、forループの使用は比較的簡単ですが、複雑なデータ構造については、手間のビットすることができます独自のコードのトラバーサルを書くと感じるかもしれませんので、ある程度イテレータパターンを減らすために...

Jul 23, 2020 · 7 min read

Object.create()、{} vs. new object()

Jul 23, 2020 · 3 min read

typeScriptのクラス (2)

Jul 22, 2020 · 7 min read

URL入門

Jul 22, 2020 · 3 min read