class Solution:
def deleteNode(self, node):
"""
:type node: ListNode
:rtype: void Do not return anything, modify node in-place instead.
Input: head = [4,5,1,9], node = 5
Output: [4,1,9]
"""
node.val=node.next.val
node.next=node.next.next
|
Remove Nth Node From End of List
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummy=ListNode(0)
dummy.next=head
slow = fast = dummy
for i in range(n):
fast=fast.next
while fast and fast.next:
fast=fast.next
slow=slow.next
slow.next=slow.next.next
return dummy.next |
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
# Step 1: Define dummy node to handle edge case of removing head
dummy = ListNode(0)
dummy.next = head
fast = slow = dummy
# Step 2: Move fast pointer n+1 steps ahead
for _ in range(n + 1):
fast = fast.next
print(fast)
# Step 3: Move both pointers until fast pointer reaches the end
while fast != None:
fast = fast.next
slow = slow.next
# Step 4: Remove the nth node from the end
slow.next = slow.next.next
return dummy.next |
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
prev = None #因為要反轉 + list的最後一個值一定是None
while head:
next1 = head.next #[1,2,3,4,5] [2,3,4,5] [3,4,5]
head.next = prev # [1,none] [2,1,none] [3,2,1,none]
prev = head #[1,none] [2,1,none] [3,2,1,none]
head = next1 #[2,3,4,5] [3,4,5] [4,5]
return prev; |
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
dummy=ListNode(0)
current=dummy
while list1 and list2:
if list1.val>=list2.val:
current.next=list2
current=current.next
list2=list2.next
else:
current.next=list1
current=current.next
list1=list1.next
if list1:
current.next=list1
elif list2:
current.next=list2
return dummy.next |
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
# Create a dummy node as the starting point of merged list
dummy_head = ListNode(0)
current = dummy_head
p1, p2 = list1, list2
# Traverse both lists and merge
while p1 and p2:
if p1.val <= p2.val:
current.next = p1
p1 = p1.next
else:
current.next = p2
p2 = p2.next
current = current.next
# Attach the remaining nodes of list1 or list2
if p1:
current.next = p1
elif p2:
current.next = p2
# Return the merged list, skipping the dummy head
return dummy_head.next |
在這段程式碼中,我們使用了 dummy_head
這個虛擬的節點作為合併後鏈表的起始點。這樣做的原因是為了簡化鏈表操作,特別是在開始時和結束時的處理:
虛擬節點
dummy_head
的用途:dummy_head
是一個空的節點,其next
指向真正的合併後的鏈表的頭部。這樣一來,在建構鏈表的過程中,我們可以直接操作dummy_head.next
而不用單獨處理頭部節點的特殊情況。
為何返回
dummy_head.next
而不是current
?:- 當我們完成遍歷並合併兩個鏈表後,
current
已經指向了合併後鏈表的最後一個節點。然而,由於current
在遍歷過程中一直在移動,最終會指向None
。 - 因此,直接返回
current
是不合適的,因為它是None
,而不是合併後的鏈表的頭部節點。 - 反之,
dummy_head.next
始終指向合併後的鏈表的頭部,即使dummy_head
是一個虛擬節點,但其next
指向的節點是我們要返回的合併後鏈表的頭部。
- 當我們完成遍歷並合併兩個鏈表後,
因此,為了返回正確的結果,我們應該返回 dummy_head.next
,而不是 current
。這樣做可以確保我們返回的是合併後鏈表的正確頭部節點,同時也符合我們在開始時使用 dummy_head
的設計思路。
current = dummy_head
這行程式碼確實是將指針 current
設置為指向 dummy_head
的意思。current 的初始化:
- 當我們寫
current = dummy_head
時,我們實際上是將current
這個指針指向了dummy_head
。這樣做是非常有用的,因為在之後的遍歷過程中,我們可以使用current
來迭代並建構合併後的鏈表。 - 最初的
dummy_head
是一個空節點,而current
則是用來追踪我們合併後鏈表的最後一個節點。
- 當我們寫
為何這樣可以設置成功?:
- 在 Python 中,對象的指針賦值是基於參考的。當我們寫
current = dummy_head
時,current
實際上指向了dummy_head
在記憶體中的位置。 - 因此,當我們後續對
current
進行操作時,例如current.next = some_node
,這個操作也會同時影響到dummy_head
,因為它們實際上是指向同一個物件的不同名稱。 - 這種設計方式讓我們可以更加方便地管理鏈表,特別是在需要進行頭部插入或者在開始處理前沒有有效節點的情況下。
- 在 Python 中,對象的指針賦值是基於參考的。當我們寫
總結來說,current = dummy_head
的設置是為了方便我們在合併兩個鏈表的過程中操作,而不必擔心初始條件的複雜性。
解法解析
初始化
- 首先,我們建立一個新的空節點
dummy_head
作為合併後鏈表的起始點。然後再設置一個指針current
指向dummy_head
,用來遍歷並構建合併後的鏈表。
- 首先,我們建立一個新的空節點
合併過程
- 我們使用兩個指針
p1
和p2
分別指向兩個待合併鏈表的頭部list1
和list2
。 - 逐一比較
p1
和p2
指向節點的值,將值較小的節點接到current.next
,並將current
往後移動一位 (current = current.next
)。 - 當其中一個鏈表遍歷完畢後,將剩餘未遍歷完的鏈表部分直接接到
current.next
。
- 我們使用兩個指針
結束
- 最後返回
dummy_head.next
即可,這是因為dummy_head
是一個空節點,真正的合併後鏈表的頭部是從dummy_head.next
開始的。
class Solution:
def isPalindrome(self, head: Optional[ListNode]) -> bool:
record=[]
while head:
record.append(head.val)
head=head.next
for i in range(len(record)//2):
if record[i]!=record[-1-i]:
return False
return True |
class Solution:
def isPalindrome(self, head: Optional[ListNode]) -> bool:
fast = slow = head
while fast and fast.next:
fast=fast.next.next
slow=slow.next
pre=None
while slow:
next1=slow.next
slow.next=pre
pre=slow
slow=next1
first_half = head
second_half = pre
while second_half:
if first_half.val != second_half.val:
return False
first_half = first_half.next
second_half = second_half.next
return True |
快慢指針來找出陣列(或鏈表)的中心點。讓我們來解釋一下:
假設有一個陣列(或鏈表),我們使用兩個指針A和B:
- A每次走兩步:
A = A + 2
- B每次走一步:
B = B + 1
當A無法再走兩步時(即A
已經達到陣列的末尾或超出了範圍),這時B所在的位置通常會是整個陣列的中心點。這是因為A每次走兩步,B每次走一步,所以當A走到末尾時,B大概就是A所走過的一半路程。
class Solution:
def hasCycle(self, head: Optional[ListNode]) -> bool:
slow = fast = head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
if slow == fast:
return True
return False |
A: 不完全正確。當我們說 slow
和 fast
是 ListNode
類型的變量時,它們實際上是指向鏈表中某個節點的指針,而不是鏈表中的整個節點。
讓我們澄清一下:
ListNode 的結構:
ListNode
是一個類型,用來表示鏈表中的每個節點。- 每個
ListNode
對象具有兩個屬性:val
:表示節點的值。next
:指向下一個節點的指針,如果是最後一個節點則為None
。
slow 和 fast 的意義:
slow
和fast
是指向ListNode
類型對象的指針。- 在解決鏈表問題時,
slow
和fast
指針分別指向鏈表中的某個節點,通常是從頭部開始。 - 例如,如果鏈表的頭部是
head
,則slow
和fast
可以初始化為head
,即slow = head
和fast = head
。
比較節點:
- 當我們說
slow
和fast
指向同一個節點時,例如ListNode{val: 1, next: ListNode{val: 2, next: ListNode{val: 4, next: None}}}
,這意味著它們的指針都指向這個具體的節點物件。 - 但在實際情況下,
slow
和fast
通常不會指向同一個節點,因為它們的遍歷速度不同(slow
每次移動一步,fast
每次移動兩步)。
- 當我們說
判斷是否有環:
- 當使用快慢指針來判斷鏈表是否有環時,我們會遍歷鏈表並移動這兩個指針。
- 如果存在環,
fast
指針最終會追上slow
指針,即它們會指向同一個節點,這時可以確定鏈表中存在環。 - 如果不存在環,
fast
指針會先到達鏈表尾部,即指向None
,此時slow
和fast
不會指向同一個節點。
總結來說,slow
和 fast
是用來遍歷和判斷鏈表結構的指針,它們不是鏈表中節點的整體表示,而是指向鏈表中特定節點的指標。
在上面提到的例子中:
- 如果我們設置
slow = head
和fast = head
,然後根據上述步驟移動指針,當slow
和fast
同時指向節點ListNode{val: 4, next: None}
時,這意味著它們指向了同一個節點。 - 如果此時
slow == fast
,則我們可以確定這個鏈表中存在環。
總結來說,節點的形式像 ListNode{val: 1, next: ListNode{val: 2, next: ListNode{val: 4, next: None}}}
只是用來表示鏈表的結構,而快慢指針 slow
和 fast
是實際用來遍歷和判斷鏈表是否有環的指針變量。
沒有留言:
張貼留言
喜歡我的文章嗎? 喜歡的話可以留言回應我喔! ^^