LeetCodeの交差リンクリスト(160)、分割リンクリスト(725)

1.交差するリンクリスト(160)

タイトル説明:

[簡単な質問]
2つの単一リンクリストが交差する開始ノードを見つけるプログラムを作成します。

次の2つのリンクリストなど。

ここに画像の説明を挿入します
交差点はノードc1から始まります。

例1:
ここに画像の説明を挿入します

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

トピックリンクの
アイデアの分析

解決策1:暴力法

  • リンクリストAのノードごとに、リンクリストBに移動してトラバースし、同じノードがあるかどうかを確認します。
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        if not headA or not headB:
            return None
        pA=headA
        while pA:
            pB=headB
            while pB:
                if pA==pB:
                    return pA
                pB=pB.next
            pA=pA.next           
  • 制限時間を超えました
  • 時間計算量:O(M ∗ N)O(M * N)O MN 、M、Nは、それぞれ2つのリンクリストの長さです。
  • スペースの複雑さ:O(1)O(1)O 1

問題解決策2:ハッシュテーブル

  • 最初にリンクリストAをトラバースし、ハッシュテーブルを使用して各ノードを記録します(ノード値ではなくノード参照を保存する必要があることに注意してください)。
  • 次に、リンクリストBをトラバースし、ハッシュテーブルに表示されているノードが2つのリンクリストの共通部分であることを確認します。
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        if not headA or not headB:
            return None
        hashmap=set()
        pA=headA
        while pA:
            hashmap.add(pA)
            pA=pA.next
        pB=headB
        while pB:
            if pB in hashmap:
                return pB
            pB=pB.next
        return None
  • 時間計算量:O(m + n)O(m + n)O m+n
  • スペースの複雑さ:O(m)O(m)O m

問題解決策3:ダブルポインター

1.リンクリストAの長さがa + cであり、リンクリストBの長さがb + cであると仮定します。ここで、cはテールの共通部分の長さであり、a + c + b =であることがわかります。 b + c + a。

2. 2つのポインタpAとpBを作成します。これらは、それぞれリンクリストAとBのヘッドノードとして初期化されます。次に、ノードごとに後方にトラバースさせます。

3.リンクリストAにアクセスするポインタpAがリンクリストの最後に到達したら、リンクリストBの先頭から開始してリンクリストBにアクセスします。同様に、リンクリストBにアクセスするポインタpBがリンクリストBにアクセスする場合も同様です。リンクリストの最後に到達したら、リンクリストAの最後から開始します。ヘッドはリンクリストAへのアクセスを開始します。pAとpBが特定の瞬間に出会う場合、pA / pBは交差ノードです。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        pA, pB = headA, headB
        while pA != pB:
            pA = pA.next if pA else headB
            pB = pB.next if pB else headA
        return pA
  • 時間計算量:O(m + n)O(m + n)O m+n
  • スペースの複雑さ:O(1)O(1)O 1

2.リンクリストの分割(725)

タイトル説明:

【中】

ヘッドノードがルートであるリンクリストが与えられた場合、リンクリストをk個の連続する部分に分割する関数を記述します。

各パーツの長さは可能な限り等しくする必要があります。2つのパーツ間の長さの差は1を超えることはできません。つまり、一部のパーツがnullになる可能性があります。

k個のパーツは、リンクリストに表示される順序で出力され、前面のパーツの長さは背面の長さ以上である必要があります。

上記のルールを満たすリンクリストのリストを返します。

例:1-> 2-> 3-> 4、k = 5 // 5結果[[1]、[2]、[3]、[4]、null]

例1:

输入: 
root = [1, 2, 3], k = 5
输出: [[1],[2],[3],[],[]]
解释:
输入输出各部分都应该是链表,而不是数组。
例如, 输入的结点 root 的 val= 1, root.next.val = 2, \root.next.next.val = 3, 且 root.next.next.next = null。
第一个输出 output[0] 是 output[0].val = 1, output[0].next = null。
最后一个元素 output[4] 为 null, 它代表了最后一个部分为空链表。

トピックリンク

思考分析

1.最初にリンクリストを走査して、リンクリストの長さを計算しますtotal_len

2、kは、割り当てられる各セグメントの全長を除算することによって得られ基础长度ますbasic_len= total_len // k

図3に示すように、上面長さの要求部分の対象は長さ以上でなければならず、後部長さの差は1を超えることはできないので、kを割ることによって得られる全長余数 m前 m 段每段的长度为:basic_len + 1;である。

4.次に、2層のループが必要です。外側のループはk個のセグメントをトラバースし、毎回現在のノードを結果リストに追加します。

5.内側のループは各セグメントのサイズをトラバースし、ポインターを後方に移動します:cur = cur.next、割り当てられるべきセグメントの長さに達するまで、このセグメントは切り捨てられ、次のリンクリストは引き続き後続のループで割り当てられます。現在のノードcurが存在する必要があるという内部ループの前提条件に特に注意してください。curがNullの場合、cur.nextが存在しないとエラーが報告されます。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def splitListToParts(self, root: ListNode, k: int) -> List[ListNode]:
        # 链表总长度
        total_len=0
        cur=root
        while cur:
            total_len+=1
            cur=cur.next
        # 每段的基础长度
        basic_len=total_len // k
        # 余数,前m段需要在基础长度加1
        m=total_len % k
        res=[]
        cur=root
        for i in range(k):
            res.append(cur)
            # 算出每段的长度
            size=basic_len + (1 if m>0 else 0)
            if cur:
                for j in range(size-1):
                    cur=cur.next
                m-=1
                tmp=cur.next # 把后面一段截掉,后面一段需要在后面继续划分
                cur.next=None
                cur=tmp
        return res
  • 時間計算量:O(n + k)O(n + k)O n+k
  • スペースの複雑さ:O(k)O(k)O k

おすすめ

転載: blog.csdn.net/weixin_45666566/article/details/113336143