leetcode-链表
链表的定义:
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
1、移除链表元素(done)
203 移除链表元素
移除头结点和移除其他节点的操作是不一样的,因为链表的其他节点都是通过前一个节点来移除当前节点,而头结点没有前一个节点。所以可以设置一个虚拟头结点,这样原链表的所有节点就都可以按照统一的方式进行移除了;return 头结点的时候,别忘了 return dummy.next,这才是新的头结点。
class Solution:
def removeElements(self, head: ListNode, val: int) -> ListNode:
dummy = ListNode(next=head) #添加一个虚拟节点
h = dummy
while h.next:
if h.next.val == val:
h.next = h.next.next
else:
h = h.next
return dummy.next #不是返回h
2、设计链表(不会)
class ListNode:
def __init__(self, x):
self.val = x
self.next = None
class MyLinkedList:
def __init__(self):
self.size = 0
self.head = ListNode(0) # 虚拟头部节点
def get(self, index: int) -> int:
# if index is invalid
if index < 0 or index >= self.size:
return -1
curr = self.head
# index steps needed
# to move from sentinel node to wanted index
for _ in range(index + 1):
curr = curr.next
return curr.val
def addAtHead(self, val: int) -> None:
self.addAtIndex(0, val)
def addAtTail(self, val: int) -> None:
self.addAtIndex(self.size, val)
def addAtIndex(self, index: int, val: int) -> None:
if index > self.size:
return
if index < 0: #负数,插入头部
index = 0
self.size += 1
# find predecessor of the node to be added
pred = self.head
for _ in range(index):
pred = pred.next
# node to be added
to_add = ListNode(val)
# insertion itself
to_add.next = pred.next
pred.next = to_add
def deleteAtIndex(self, index: int) -> None:
# if the index is invalid, do nothing
if index < 0 or index >= self.size:
return
self.size -= 1
# find predecessor of the node to be deleted
pred = self.head
for _ in range(index):
pred = pred.next
# delete pred.next
pred.next = pred.next.next
3、反转链表(done)
- 首先定义一个cur指针,指向头结点,再定义一个pre指针,初始化为null。
- 把 cur->next 节点用tmp指针保存一下,也就是保存一下这个节点, 将cur->next 指向pre。
- cur 指针已经指向了null,循环结束,链表也反转完毕了。 此时我们return pre指针就可以了。
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
pre = None #虚拟头节点,不能用ListNode(None)
cur = head
while cur:
temp = cur.next #保存一下 cur的下一个节点,因为接下来要改变cur->next
cur.next = pre #翻转指针
#更新pre、cur指针
pre = cur
cur = temp
return pre
4、两两交换链表中的节点(not done)
24. 两两交换链表中的节点
创建哑结点 dummyHead,令 dummyHead.next = head。令 temp 表示当前到达的节点,初始时 temp = dummyHead。每次需要交换 temp 后面的两个节点。
如果 temp 的后面没有节点或者只有一个节点,则没有更多的节点需要交换,因此结束交换。否则,获得 temp 后面的两个节点 node1 和 node2,通过更新节点的指针关系实现两两交换节点。
具体而言,交换之前的节点关系是 temp -> node1 -> node2,交换之后的节点关系要变成 temp -> node2 -> node1,因此需要进行如下操作。
temp.next = node2
node1.next = node2.next
node2.next = node1
完成上述操作之后,节点关系即变成 temp -> node2 -> node1。再令 temp = node1,对链表中的其余节点进行两两交换,直到全部节点都被两两交换。
两两交换链表中的节点之后,新的链表的头节点是 dummyHead.next,返回新的链表的头节点即可。
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
dummyHead = ListNode(next=head)
temp = dummyHead
while temp.next and temp.next.next:
node1 = temp.next
node2 = temp.next.next
temp.next = node2
node1.next = node2.next
node2.next = node1
temp = node1
return dummyHead.next
5、删除链表倒数第N个节点(done)
19. 删除链表倒数第N个节点
要删除倒数第n个节点,让fast移动n步,然后让fast和slow同时移动,直到fast指向链表末尾。删掉slow所指向的节点即可。
- 定义fast指针和slow指针,初始值为虚拟头结点;
- fast首先走n ;
- fast和slow同时移动,直到fast指向末尾;
- 删除slow指向的下一个节点
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
dummy =ListNode(next=head)
l = dummy
f = head
for i in range(n):
f = f.next
while f:
l = l.next
f = f.next
l.next = l.next.next #删除
return dummy.next
6、链表相交(done while A != B:)
0207. 链表相交
根据快慢法则,走的快的一定会追上走得慢的。
在这道题里,有的链表短,他走完了就去走另一条链表,我们可以理解为走的快的指针。那么,只要其中一个链表走完了,就去走另一条链表的路。如果有交点,他们最终一定会在同一个位置相遇。
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
if not headA or not headB:
return None
A = headA
B = headB
while A != B:
A = A.next if A else headB # 如果a走完了,那么就切换到b走
B = B.next if B else headA #同理,b走完了就切换到a
return A
7、环形链表II(done 不是比较val)
142. 环形链表II
分别定义 fast 和 slow指针,从头结点出发,fast指针每次移动两个节点,slow指针每次移动一个节点,如果 fast 和 slow指针在途中相遇 ,说明这个链表有环。
class Solution:
def detectCycle(self, head: ListNode) -> ListNode:
slow, fast = head, head
while fast and fast.next:
slow = slow.next
fast = fast.next.next
# 如果相遇
if slow == fast:
p = head
q = slow
while p!=q:
p = p.next
q = q.next
#你也可以return q
return p
return None
8、两数相加
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode(0)
pre = dummy
s = 0 #进位
while l1 or l2 or s :
s += (l1.val if l1 else 0) + (l2.val if l2 else 0)
pre.next = ListNode(s%10)
pre = pre.next
if l1: l1 = l1.next
if l2: l2 = l2.next
s //= 10
return dummy.next
9、链表相加(二)
25. 链表中的两数相加
本题的主要难点在于链表中数位的顺序与我们做加法的顺序是相反的,为了逆序处理所有数位,我们可以使用栈:把所有数字压入栈中,再依次取出相加。
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
s1, s2 = [], []
while l1:
s1.append(l1.val)
l1 = l1.next
while l2:
s2.append(l2.val)
l2 = l2.next
ans = None
s = 0 #进位
while s1 or s2 or s:
a = 0 if not s1 else s1.pop() #l1倒序
b = 0 if not s2 else s2.pop() #l2倒序
cur = a + b + s
s = cur // 10
cur %= 10
curnode = ListNode(cur)
curnode.next = ans
ans = curnode
return ans
方法二:先反转l1,l2,相加后再反转结果
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
head1,head2 = self.reverse(l1),self.reverse(l2)
dummy = ListNode(0)
pre = dummy
s = 0 #进位
while s or head1 or head2:
s += (head1.val if head1 else 0) + (head2.val if head2 else 0)
pre.next = ListNode(s%10)
pre = pre.next
if head1: head1 = head1.next
if head2: head2 = head2.next
s //= 10
return self.reverse(dummy.next )
def reverse(self, head: ListNode):
pre = None
cur = head
while cur:
tmp = cur.next #保存节点
cur.next = pre
#更新
pre = cur
cur = tmp
return pre
10、旋转链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def rotateRight(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
if k == 0 or not head or not head.next:
return head
#计算链表长度
n = 1
cur = head
while cur.next:
cur = cur.next
n += 1
# k 为 n 的倍数时,新链表将与原链表相同
if k % n == 0:
return head
#将链表的末尾节点,与头节点相连
cur.next = head
add = n - k % n
while add:
cur = cur.next
add -= 1
ret = cur.next
cur.next = None
return ret
剑指 Offer
8、 从尾到头打印链表(done)
class Solution:
def reversePrint(self, head: ListNode) -> List[int]:
stack = []
while head:
stack.append(head.val)
head = head.next
return stack[::-1]
9、 合并两个排序的链表(done)
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
dummpy = ListNode(None)
cur = dummpy
while l1 and l2:
if l1.val < l2.val:
cur.next = l1
l1 = l1.next
else:
cur.next = l2
l2 = l2.next
cur = cur.next
cur.next = l1 if l1 else l2
return dummpy.next
10、两个链表的第一个公共结点(双指针done)
- 只有当链表headA 和 headB 都不为空时,两个链表才可能相交。因此首先判断链表headA 和 headB是否为空,如果其中至少有一个链表为空,则两个链表一定不相交,返回 null。
- 当链表headA 和 headB 都不为空时,创建两个指针pA 和pB,初始时分别指向两个链表的头节点headA 和headB,然后将两个指针依次遍历两个链表的每个节点。具体做法如下:
每步操作需要同时更新指针pA 和pB。
如果指针pA 不为空,则将指针pA 移到下一个节点;如果指针pB 不为空,则将指针pB 移到下一个节点。
如果指针pA 为空,则将指针pA 移到链表 headB 的头节点;如果指针pB 为空,则将指针pB 移到链表headA 的头节点。
当指针pA 和pB 指向同一个节点或者都为空时,返回它们指向的节点或者 null。
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
if not headA or not headB:
return None
node1,node2 = headA,headB
while node1 != node2:
node1 = node1.next if node1 else headB
node2 = node2.next if node2 else headA
return node1
11、链表中倒数最后k个结点(done)
class Solution:
def FindKthToTail(self , pHead: ListNode, k: int) -> ListNode:
if not pHead:
return pHead
slow,fast = pHead,pHead
for _ in range(k):
if fast:
fast = fast.next
else:
return None #k大于链表长度
while fast:
fast = fast.next
slow = slow.next
return slow
12、删除排序链表中的重复元素 II(done)
82 删除排序链表中的重复元素 II
由于链表的头节点可能会被删除,因此我们需要额外使用一个哑节点(dummy node)指向链表的头节点。
具体地,我们从指针cur 指向链表的哑节点,随后开始对链表进行遍历。如果当前 cur.next 与cur.next.next 对应的元素相同,那么我们就需要将 cur.next 以及所有后面拥有相同元素值的链表节点全部删除。我们记下这个元素值 xx,随后不断将 cur.next 从链表中移除,直到 cur.next 为空节点或者其元素值不等于 x 为止。此时,我们将链表中所有元素值为 x 的节点全部删除。
如果当前 cur.next 与cur.next.next 对应的元素不相同,那么说明链表中只有一个元素值为 cur.next 的节点,那么我们就可以将cur 指向 cur.next。
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
if not head:
return head
dummy = ListNode(0, head)
cur = dummy
while cur.next and cur.next.next:
if cur.next.val == cur.next.next.val:
x = cur.next.val
while cur.next and cur.next.val == x:
cur.next = cur.next.next
else:
cur = cur.next
return dummy.next
13、复杂链表的复制(……不会)
14、二叉搜索树与双向链表
class Solution:
def treeToDoublyList(self, root: 'Node') -> 'Node':
if not root:
return None
ans = []
def dfs(root):
if root:
dfs(root.left)
ans.append(root)
dfs(root.right)
dfs(root)
if len(ans) == 1:
return root
# 构造双向链表
for i in range(len(ans)-1):
ans[i].right = ans[i+1]
ans[i+1].left = ans[i]
return ans[0]