基礎解:荷蘭國旗問題(筆試時可用,簡單直接,但不穩定)
將所有的節點遍歷得到鏈表的長度,再遍歷一次將所有節點放置到一個數組中,對這個數組進行partition調整(荷蘭國旗問題),再將每個數組中每個節點串起來即可。
進階解:按照原鏈表各個節點的對應順序將鏈表調整成三部分,小於num的、等於num的,大於num的,之後再將三個連起來即可。
代碼如下:
#coding=utf-8
'''
將單向鏈表按某值劃分成左邊小、 中間相等、 右邊大的形式
【 題目】 給定一個單向鏈表的頭節點head, 節點的值類型是整型, 再給定一個
整 數pivot。 實現一個調整鏈表的函數, 將鏈表調整爲左部分都是值小於 pivot
的節點, 中間部分都是值等於pivot的節點, 右部分都是值大於 pivot的節點。
除這個要求外, 對調整後的節點順序沒有更多的要求。 例如: 鏈表9->0->4->5-
>1, pivot=3。 調整後鏈表可以是1->0->4->9->5, 也可以是0->1->9->5->4。 總
之, 滿 足左部分都是小於3的節點, 中間部分都是等於3的節點(本例中這個部
分爲空) , 右部分都是大於3的節點即可。 對某部分內部的節點順序不做 要求。
進階: 在原問題的要求之上再增加如下兩個要求。
在左、 中、 右三個部分的內部也做順序要求, 要求每部分裏的節點從左 到右的
順序與原鏈表中節點的先後次序一致。 例如: 鏈表9->0->4->5->1, pivot=3。
調整後的鏈表是0->1->9->4->5。 在滿足原問題要求的同時, 左部分節點從左到
右爲0、 1。 在原鏈表中也 是先出現0, 後出現1; 中間部分在本例中爲空, 不再
討論;右部分節點 從左到右爲9、 4、 5。 在原鏈表中也是先出現9,然後出現4,
最後出現5。
如果鏈表長度爲N,時間複雜度請達到O(N),額外空間複雜度請達到O(1)。
'''
class Node(object):
"""單向鏈表的結點"""
def __init__(self,elem):
self.elem=elem
self.next=None
class SingleLinkList(object):
"""單鏈表"""
def __init__(self,node=None):
"""構造函數"""
self.__head=node #頭節點
def getHead(self):
return self.__head
def travel(self):
"""遍歷鏈表"""
cur=self.__head
while cur!=None:
print(cur.elem,end=" ")
cur=cur.next
print("")
def add(self,item):
"""鏈表頭部添加元素
O(1)
"""
node=Node(item)
node.next=self.__head
self.__head=node
def listPartition1(self,num):#這種方法最快,但做不到穩定性,數組需要額外空間。
#普通問題
#時間複雜度是 O(N),空間複雜度是 O(N)
#首先遍歷一遍鏈表,得到鏈表的長度,將鏈表元素依次放到數組中,然後利用類似於快速排序中的partition 思想進行分割
#partition完之後再串成鏈表
if self.__head is None: #空鏈表
return self.__head
cur=self.__head
i=0
while cur: #遍歷一次鏈表,統計元素個數即鏈表長度
cur=cur.next
i+=1
#將鏈表中的每個元素依次放入到數組中
nodeArr=[]
cur=self.__head
for j in range(0,i):
nodeArr.append(cur)
cur=cur.next
# print(i)
#進行類似快速排序的partition
nodeArr=self.arrPartition(nodeArr,num)
#重新連接各個鏈表節點
for q in range(1,i):
nodeArr[q-1].next=nodeArr[q]
nodeArr[i-1].next=None
return nodeArr
def arrPartition(self,nodeArr,num):
left=-1
right=len(nodeArr)
index=0
while index<right:
if nodeArr[index].elem<num:
left += 1
nodeArr[left],nodeArr[index]=nodeArr[index],nodeArr[left] #交換
index+=1
elif nodeArr[index].elem==num:
index+=1
else:
right -= 1
nodeArr[right], nodeArr[index] = nodeArr[index], nodeArr[right] ##交換
return nodeArr
def listPartition2(self,num):#測試通過
'''
* 進階問題: 保證各部分內部的順序與原來鏈表中各個節點的順序相同
* 時間複雜度是 O(N),空間複雜度是 O(1)
* 考察 利用有限的幾個變量來調整鏈表的代碼實現能力。
1.將鏈表分爲三部分:small,equal,more
small:2->1->null
equal:5->5->null
more:9->7->8->null
2.將small、equal、more三個鏈表重新串起來
3.整個過程需要特別注意對null節點的判斷和處理
'''
less=Node(None)
endless=Node(None)
equal=Node(None)
endequal=Node(None)
more=Node(None)
endmore=Node(None)
#every node distributed to three lists
while self.__head:
Next=self.__head.next
self.__head.next=None
if self.__head.elem<num:
if less.elem is None:
less=self.__head
endless=self.__head
else:
endless.next=self.__head
endless=endless.next
elif self.__head.elem==num:
if equal.elem is None:
equal=self.__head
endequal=self.__head
else:
endequal.next=self.__head
endequal=self.__head
elif self.__head.elem>num:
if more.elem is None:
more =self.__head
endmore=self.__head
else:
endmore.next=self.__head
endmore=self.__head
self.__head=Next
# small and equal reconnect
if endless.elem and equal.elem:
endless.next=equal
endequal=endequal if endequal.elem else endless
# all reconnect
if endequal.elem:
endequal.next=more
endmore=endmore if endmore.elem else endequal
res=equal if equal.elem else more
res=less if less.elem else res #返回鏈表頭節點
return res
def printLinkedList(self,node):
print("Linked List:")
while node.next:
print(node.elem,end=" ")
node=node.next
print(node.elem)
print("")
if __name__=="__main__":
s1 = SingleLinkList()
s1.add(7)
s1.add(9)
s1.add(1)
s1.add(8)
s1.add(3)
s1.add(5)
s1.add(2)
s1.add(5)
s1.add(5)
s1.add(4)
s1.add(3)
s1.travel()
# res=s1.listPartition1(5)
# s1.printLinkedList(res[0])
res=s1.listPartition2(6) #bug:如果沒有等於num的鏈表就斷掉了
s1.printLinkedList(res)
運行結果如下:
等程序無bug再粘