本題目摘自《Python程序員面試算法寶典》,我會每天做一道這本書上的題目,並分享出來,統一放在我博客內,收集在一個分類中。
【微軟筆試題】
難度系數:⭐⭐⭐
考察頻率:⭐⭐⭐⭐⭐
題目描述:
找出單鏈表中的倒數第k個元素,例如給定單鏈表:1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7,則單鏈表的倒數第3個元素為5.
方法一:順序遍歷法
這種方法需要對單鏈表進行兩次遍歷,第一次遍歷得到單鏈表的長度,這樣我們在第二次遍歷過程中就知道了什么時候找到了我們需要的那個元素了。
方法二:快慢指針法
由於單鏈表只能從頭到尾巴依次訪問鏈表的各個結點,因此如果我們要找鏈表的倒數第k個元素,也只能從頭到尾巴遍歷查找,設置兩個指針,讓其中一個指針比令一個指針先走k步(如果第k個元素存在的話),然后兩個指針同時向后走,直到快指針走到最后一個元素,這時候慢指針所指向的位置就是要找的元素了。
兩個方法的代碼如下:
class Node: # 結點類
def __init__(self, data):
self.data = data
self.next = None
class SingleLinkList: # 單鏈表類
def __init__(self):
self.head = None
self.tail = None
def append(self, x): # 單鏈表尾部追加方法
if self.head is None:
self.head = self.tail = Node(x)
else:
self.tail.next = Node(x)
self.tail = self.tail.next
# 創建鏈表
test_link = SingleLinkList()
for i in range(1, 8):
test_link.append(i)
# 打印鏈表看一下
p = test_link.head
print("鏈表:", end="\t")
while p is not None:
print(p.data, end="\t")
p = p.next
print()
# 方法一 順序遍歷法
def find_it(link: SingleLinkList, k):
# 第一步獲取長度
i = 0
p = link.head
while p is not None: # 循環完成后 i就是鏈表的長度
i += 1
p = p.next
if i < k:
return None
j = 0
p = link.head
while i - j > k: # 循環完成后 p就是倒數第三個結點
p = p.next
j += 1
return p.data
# 測試方法一
t = test_link
k = 5
print(f"倒數第{k}個元素是:", find_it(t, k), "(順序遍歷法)")
# 方法二 快慢指針法
def find_it(link: SingleLinkList, k):
slow = link.head # slow指向第一個元素
j = 1
p = link.head
while p is not None: # 如果鏈表的元素個數少於k, return None
p = p.next
j += 1
if j >= k:
break
else:
return None
fast = p # fast指向第k個元素
while fast.next is not None: # 循環結束之后fast指向最后一個元素,slow指向倒數第k個元素
slow = slow.next
fast = fast.next
return slow.data
# 測試方法二
t = test_link
k = 5
print(f"倒數第{k}個元素是:", find_it(t, k), "(快慢指針法)")
兩個方法的時間復雜度都是O(n),不同在於方法一最壞可能要遍歷兩遍,方法二只需要遍歷一遍。