Pythonアルゴリズム(三、1)チェーンテーブル
80370 ワード
1、一つのチェーンテーブルが回文構造であるかどうかを判断する
チェーンテーブルのヘッダノードheadを指定し、チェーンテーブルが返信構造であるかどうかを判断します.たとえば、1->2->1でtrueを返します.1->2->2->1、trueを返します.15->6->15、trueを返します.1->2->3でfalseを返します.ステップアップ:チェーンテーブル長がNの場合、時間的複雑度はO(N)に達し、余分な空間的複雑度はO(1)に達する.
構想1:遍歴中、すべての結果をスタックに入れ、逆順序と元の構造が同じかどうかを確認し、空間複雑度o(N)
考え方2:中間後ろの結果をスタックに入れて、一緒に比較して、0(N/2)
考え方3:遅いポインタは中間位置を指し、要素を空にし、速いポインタは中間の1つを指し、後ろの要素を前に指します.空間複雑度o(1)
2、オランダ国旗チェーンの問題
構想1:ノードを配列構造に直接入れ,並べ替えた後,接続を遍歴する.空間複雑度O(N)
構想2:空間複雑度o(1)は,6つの変数タグstartとendの変数less,eq,moreを用意し,もう1つの一時タグの次の数を用意する.遍歴、対応する値を対応する遍歴の下 に掛ける.最後に3つの変数を に接続する.
3、ランダムポインタノードを含むチェーンテーブルをコピーする
ノードクラスのvalueはノード値であり、nextポインタは通常の単一チェーンテーブルのnextポインタと同様に、次のノードを指します.randポインタはノードクラスに追加されたポインタで、チェーンテーブルのいずれかのノードを指したり、nullを指したりすることができます.Nodeノードタイプからなるループレス単一チェーンテーブルのヘッダノードheadを指定します.このチェーンテーブル内のすべての構造のコピーを完了し、コピーした新しいチェーンテーブルのヘッダノードを返す関数を実装します.ステップアップ:追加のデータ構造を使用せず、有限数の変数のみを使用し、時間的複雑度O(N)内で元の問題を実現する関数を完了します.
構想1:ハッシュテーブルを用意し,元のノードと新しいノードをkv形式で格納し,遍歴する
構想2:元のノードを複製して、1、チェーンテーブルを再構築するのは1->1’->2->2’->3->3’2、一度に2つのノードを取り出して、もしノード1と1’ならば、主にrandポインタの問題を取得して、ここで1のrandポインタは3で、3のnextポインタは3’3で、それから1’のrandポインタを3’に設定して、順次すべての複製を完成することができます
4、二つの単一チェーンテーブルの交差問題
単一チェーンテーブルにはリングがあるかもしれないし、リングがないかもしれない.2つの単一チェーンテーブルのヘッダノードhead 1およびhead 2が与えられ、この2つのチェーンテーブルは交差するか、交差しないかのいずれかである.2つのチェーンテーブルが交差している場合は、交差する最初のノードを返します.交差しない場合はnullを返します.要求:チェーンテーブル1の長さがN、チェーンテーブル2の長さがM、時間複雑度がO(N+M)、余分な空間複雑度がO(1)に達してください.
まず、ループがあるかどうかを判断します.
考え方1:ハッシュ表を用意し、まずAチェーン表を遍歴してハッシュ表に入れ、Bチェーン表が存在するかどうかを遍歴すればよい
考え方2:2つの変数、1つの遅いポインタ、1つの速いポインタを準備します速い針は毎回2歩歩いて、遅い針は1歩 歩きますはすぐにリングにぶつかって、それから速いポインタはheadに戻って、速くゆっくり歩いて1歩ずつリングに入る位置です.逆にNoneが無環 に遭遇する
a、無環の場合は、head 1の長さ、end 1、head 2の長さ、end 2 の4つの変数を用意する. end 1はend 2に等しいリングであり、長いチェーンテーブルを別の長さに等しくしてから、一緒に遍歴すると同じ点 が見つかる.
b、一有環、一無環、交差不可能、単鎖表の定義に背く
c、すべて環の情況があって、交点の3種類の情況:交差がなくて、1つの交点、2つの交点の交点:4つの変数を用意し,ループの有無を判断し始めると,入ループノードloop,loop 1,2が等しい が得られる.無交点または2つの交点:loop 1と2は等しくなく、loop 1からloop 2に遭遇したか否かを遍歴して判断する を継続する.
チェーンテーブルのヘッダノードheadを指定し、チェーンテーブルが返信構造であるかどうかを判断します.たとえば、1->2->1でtrueを返します.1->2->2->1、trueを返します.15->6->15、trueを返します.1->2->3でfalseを返します.ステップアップ:チェーンテーブル長がNの場合、時間的複雑度はO(N)に達し、余分な空間的複雑度はO(1)に達する.
構想1:遍歴中、すべての結果をスタックに入れ、逆順序と元の構造が同じかどうかを確認し、空間複雑度o(N)
考え方2:中間後ろの結果をスタックに入れて、一緒に比較して、0(N/2)
考え方3:遅いポインタは中間位置を指し、要素を空にし、速いポインタは中間の1つを指し、後ろの要素を前に指します.空間複雑度o(1)
from queue import LifoQueue
class Node:
def __init__(self, data, next=None):
self.value = data
self.next = next
class IsPalindromeList:
def stack_method(self, head):
stack_ = LifoQueue()
cur = head
while cur is not None:
stack_.put(cur)
cur = cur.next
while head is not None:
if head.value != stack_.get().value:
return False
head = head.next
return True
# need n/2 extra space
def stack_method2(self, head):
if head == None or head.next is None:
return True
right = head.next
cur = head
while cur.next is not None and cur.next.next is not None:
right = right.next
cur = cur.next.next
stack_ = LifoQueue()
while right is not None:
stack_.put_nowait(right)
right = right.next
while not stack_.empty():
if head.value != stack_.get().value:
return False
head = head.next
return True
# need O(1) extra space
def no_stack_method(self, head):
if head == None or head.next == None:
return True
n1 = head
n2 = head
while n2.next != None and n2.next.next != None: # find mid node
n1 = n1.next # mid node
n2 = n2.next.next # end node
n2 = n1.next # right part first node
n1.next = None # mid.next-> None
while n2 != None: # right part revert
n3 = n2.next # save next node
n2.next = n1 # next of right node convert
n1 = n2 # n1 move
n2 = n3 # n2 move
# n2.next, n1 = n1, n2
n3 = n1 # save last node
n2 = head # left first node
res =True
while n1 != None and n2 != None:
if n1.value != n2.value:
res = False
break
n1 = n1.next
n2 = n2.next
# final recover linked list
n1 = n3.next
n3.next = None
while n1 != None:
n2 = n1.next
n1.next = n3
n3 = n1
n1 = n2
return res
def print_linked_list(self, node):
print('Linked List: ')
while node != None:
print(node.value, ' ')
node = node.next
print()
def main(self):
head = Node(1)
head.next = Node(2)
head.next.next = Node(3)
head.next.next.next = Node(1)
self.print_linked_list(head)
print(self.stack_method(head) , ' | ')
print(self.stack_method2(head) , ' | ')
print(self.no_stack_method(head) , ' | ')
self.print_linked_list(head)
print("1=========================")
head = Node(1)
head.next = Node(2)
head.next.next = Node(3)
head.next.next.next = Node(2)
head.next.next.next.next = Node(1)
self.print_linked_list(head)
print(self.stack_method(head) , ' | ')
print(self.stack_method2(head) , ' | ')
print(self.no_stack_method(head) , ' | ')
self.print_linked_list(head)
print("2=========================")
a = IsPalindromeList()
a.main()
2、オランダ国旗チェーンの問題
構想1:ノードを配列構造に直接入れ,並べ替えた後,接続を遍歴する.空間複雑度O(N)
構想2:空間複雑度o(1)は,6つの変数タグstartとendの変数less,eq,moreを用意し,もう1つの一時タグの次の数を用意する.
class Node:
def __init__(self, value, next=None):
self.value = value
self.next = next
class SmallerEqualBigger:
def list_partition1(self, head, pivot):
if head is None:
return head
cur = head
i = 0
while cur is not None:
i += 1
cur = cur.next
node_arr = [i for i in range(i)] #
i = 0
cur = head
for i in range(len(node_arr)):
node_arr[i] = cur
cur = cur.next
self.arr_partition(node_arr, pivot)
for i in range(1, len(node_arr)):
node_arr[i-1].next = node_arr[i]
node_arr[i-1].next = None
return node_arr[0]
def arr_partition(self, node_arr, pivot):
small = -1
big = len(node_arr)
index = 0
while index != big:
if node_arr[index].value < pivot:
small += 1
node_arr[small], node_arr[index] = node_arr[index], node_arr[small]
index += 1
elif node_arr[index].value == pivot:
index += 1
else:
big -= 1
node_arr[big], node_arr[index] = node_arr[index], node_arr[big]
def list_partition2(self, head, pivot):
sh, st, eh, et, bh, bt, next = [None for _ in range(7)]
while head != None:
next = head.next
head.next = None
if head.value < pivot:
if sh is None:
sh,st = head,head
else:
sh.next, st = head, head
elif head.value == pivot:
if eh is None:
eh,et = head,head
else:
eh.next, et = head,head
else:
if bh is None:
bh,bt = head,head
else:
bh.next,bt = head,head
head = next
if st is not None:
st.next = eh
et = st if et is None else et #
if et is not None:
et.next = bh
# return sh if sh is not None else eh if eh is not None else bh
if sh is not None:
return sh
else:
if eh is not None:
return eh
else:
return bh
def print_linked_list(self, node):
print('Linked List: ')
while node != None:
print(node.value, '')
node = node.next
print()
def main(self):
head1 = Node(7)
head1.next = Node(9)
head1.next.next = Node(1)
head1.next.next.next = Node(8)
head1.next.next.next.next = Node(5)
head1.next.next.next.next.next = Node(2)
head1.next.next.next.next.next.next = Node(5)
self.print_linked_list(self.list_partition1(head1, 5))
self.print_linked_list(self.list_partition2(head1, 5))
SmallerEqualBigger().main()
3、ランダムポインタノードを含むチェーンテーブルをコピーする
ノードクラスのvalueはノード値であり、nextポインタは通常の単一チェーンテーブルのnextポインタと同様に、次のノードを指します.randポインタはノードクラスに追加されたポインタで、チェーンテーブルのいずれかのノードを指したり、nullを指したりすることができます.Nodeノードタイプからなるループレス単一チェーンテーブルのヘッダノードheadを指定します.このチェーンテーブル内のすべての構造のコピーを完了し、コピーした新しいチェーンテーブルのヘッダノードを返す関数を実装します.ステップアップ:追加のデータ構造を使用せず、有限数の変数のみを使用し、時間的複雑度O(N)内で元の問題を実現する関数を完了します.
構想1:ハッシュテーブルを用意し,元のノードと新しいノードをkv形式で格納し,遍歴する
構想2:元のノードを複製して、1、チェーンテーブルを再構築するのは1->1’->2->2’->3->3’2、一度に2つのノードを取り出して、もしノード1と1’ならば、主にrandポインタの問題を取得して、ここで1のrandポインタは3で、3のnextポインタは3’3で、それから1’のrandポインタを3’に設定して、順次すべての複製を完成することができます
class Node:
def __init__(self, value, next=None, rand=None):
self.value = value
self.next = next
self.rand = rand
class CopyListWithRandom:
def copy_random_linked(self, head):
map = {}
cur = head
while cur is not None:
map[cur] = Node(cur.value)
cur = cur.next
cur = head
while cur is not None:
map[cur].next = map[cur.next] if cur.next is not None else None
map[cur].rand = map[cur.rand] if cur.next is not None else None
cur = cur.next
return map[head]
def copy_random_linked2(self, head):
if head is None:
return None
cur = head
# 1-1'-2-2'-3-3'-None
while cur is not None:
nor_next = cur.next
cur.next = Node(cur.value)
cur.next.next = nor_next # 1'->2
cur = nor_next
cur = head
# node rand
while cur is not None:
nor_next = cur.next.next
cur_copy = cur.next
cur_copy.rand = cur.rand.next if cur.rand is not None else None
cur = nor_next
res = head.next
cur = head
while cur is not None:
old_node = cur.next.next
copy_node = cur.next
cur.next = old_node
copy_node.next = old_node.next if old_node is not None else None
cur = old_node
return res
def print_linked_list(self, node):
print('Linked List: ')
while node != None:
print(f'next: {node.value}, rand: {node.rand.value if node.rand is not None else None}')
node = node.next
print()
def main(self):
"""
next: 1->2->3->None
random: 1->3, 2->1, 3->None
"""
head1 = Node(1)
head1.next = Node(2)
head1.next.next = Node(3)
head1.rand = head1.next.next
head1.next.rand = head1
head1.next.next.rand = None
self.print_linked_list(self.copy_random_linked(head1))
self.print_linked_list(self.copy_random_linked2(head1))
CopyListWithRandom().main()
4、二つの単一チェーンテーブルの交差問題
単一チェーンテーブルにはリングがあるかもしれないし、リングがないかもしれない.2つの単一チェーンテーブルのヘッダノードhead 1およびhead 2が与えられ、この2つのチェーンテーブルは交差するか、交差しないかのいずれかである.2つのチェーンテーブルが交差している場合は、交差する最初のノードを返します.交差しない場合はnullを返します.要求:チェーンテーブル1の長さがN、チェーンテーブル2の長さがM、時間複雑度がO(N+M)、余分な空間複雑度がO(1)に達してください.
まず、ループがあるかどうかを判断します.
考え方1:ハッシュ表を用意し、まずAチェーン表を遍歴してハッシュ表に入れ、Bチェーン表が存在するかどうかを遍歴すればよい
考え方2:2つの変数、1つの遅いポインタ、1つの速いポインタを準備します
a、無環の場合
b、一有環、一無環、交差不可能、単鎖表の定義に背く
c、すべて環の情況があって、交点の3種類の情況:交差がなくて、1つの交点、2つの交点
class Node:
def __init__(self, data, next=None):
self.value = data
self.next = next
class GetIntersectNode:
def get_intersect_node(self, head1, head2):
if head1 is None or head2 is None:
return None
loop1 = self.get_loop_node(head1)
loop2 = self.get_loop_node(head2)
#
if loop1 is None and loop2 is None:
return self.no_loop(head1, head2)
#
elif loop1 is not None and loop2 is not None:
return self.both_loop(head1, loop1, head2, loop2)
#
return None
def get_loop_node(self, head):
if head is None or head.next is None or head.next.next is None:
return None
n1 = head.next # slow pointer
n2 = head.next.next # fast pointer
while n1 != n2:
if n2.next is None or n2.next.next is None:
return None
n2 = n2.next.next
n1 = n1.next
n2 = head
#
while n1 != n2:
n1 = n1.next
n2 = n2.next
return n1
def no_loop(self, head1, head2):
if head1 is None and head2 is None:
return None
cur1 = head1
cur2 = head2
n = 0
while cur1.next is not None:
n += 1
cur1 = cur1.next
while cur2.next is not None:
n -= 1
cur2 = cur2.next
if cur1 != cur2:
return None
cur1 = head1 if n > 0 else head2 #
cur2 = head2 if cur1 == head1 else head2 # ,
n = abs(n)
while n != 0:
n -= 1
cur1 = cur1.next
while cur1 != cur2:
cur1, cur2 = cur1.next, cur2.next
return cur1
def both_loop(self, head1, loop1, head2, loop2):
cur1 = None
cur2 = None
if loop1 == loop2:
cur1,cur2,n = head1,head2,0
while cur1 != loop1:
n += 1
cur1 = cur1.next
while cur2 != loop2:
n -= 1
cur2 = cur2.next
cur1 = head1 if n>0 else head2
cur2 = head2 if cur1==head1 else head1
n = abs(n)
while 0 != n:
n -= 1
cur1 = cur1.next
while cur1 != cur2:
cur1 = cur1.next
cur2 = cur2.next
return cur1
else:
cur1 = loop1.next
while cur1 != loop1:
if cur1 == loop2:
return loop1
cur1 = cur1.next
return None
def main(self):
# 、
# 1-2-3-4-5-6-7-None
head1 = Node(1)
head1.next = Node(2)
head1.next.next = Node(3)
head1.next.next.next = Node(4)
head1.next.next.next.next = Node(5)
head1.next.next.next.next.next = Node(6)
head1.next.next.next.next.next.next = Node(7)
# 0-9-8-6-7-None
head2 = Node(0)
head2.next = Node(9)
head2.next.next = Node(8)
head2.next.next.next = head1.next.next.next.next.next # 8->6
print(self.get_intersect_node(head1, head2).value) # 6
#
# 1->2->3->4->5->6->7->4...
head3 = Node(1)
head3.next = Node(2)
head3.next.next = Node(3)
head3.next.next.next = Node(4)
head3.next.next.next.next = Node(5)
head3.next.next.next.next.next = Node(6)
head3.next.next.next.next.next.next = Node(7)
head3.next.next.next.next.next.next = head3.next.next.next # 7->4
# 0->9->8->2...
head4 = Node(0)
head4.next = Node(9)
head4.next.next = Node(8)
head4.next.next.next = head3.next # 8->2
print(self.get_intersect_node(head3, head4).value) # 2
#
# 0->9->8->6->4->5->6..
head5 = Node(0)
head5.next = Node(9)
head5.next.next = Node(8)
head5.next.next.next = head3.next.next.next.next.next # 8->6
print(self.get_intersect_node(head3, head5).value) # 6
# 6,2,6
GetIntersectNode().main()