目录
2020/8/8
160链表相交
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
curA=headA
curB=headB
#计算长度差
n=0
while(curA):
n+=1
curA=curA.next
while(curB):
n-=1
curB=curB.next
if(curA!=curB):
return None
#长链表先走【长度差】
curA=headA if n>0 else headB
curB=headB if n>0 else headA
n=abs(n)
while(n>0):
n-=1
curA=curA.next
while(curA!=curB):
curA=curA.next
curB=curB.next
return curA
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
cur1=headA
cur2=headB
while(cur1 != cur2):
cur1=cur1.next if cur1 else headB
cur2=cur2.next if cur2 else headA
return cur1
206翻转链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
pre=None
cur=head
while(cur):
temp=ListNode(cur.val)
temp.next=pre
pre=temp
cur=cur.next
return pre
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
pre=None
while(head):
temp=head.next
head.next=pre
pre=head
head=temp
return pre
21合并两个有序链表
迭代
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
#选择当前l1 l2中较小的元素
pre=ListNode(None)
cur=pre
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
pre=pre.next
return pre
83 删除排序链表中重复值
暴力解法
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
#遍历 遇到重复 就指向其下一个
if(not head):
return None
cur=head
while(cur and cur.next):
#当前是重复值
if(cur.val==cur.next.val):
cur.next=cur.next.next
#当前不重复
else:
cur=cur.next
return head
2020/8/9
19删除链表倒数第N个节点
哑节点为了两种情况:
①一个节点 ②node_num==n
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
node_nums=0
cur=head
while(cur):
node_nums+=1
cur=cur.next
cur=head
#为了包含这两种情况 可以增加哑节点
if(node_nums==1):
return None
if(node_nums==n):
return head.next
#以上
for i in range(0,node_nums-n-1):
cur=cur.next
cur.next=cur.next.next
return head
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
node_nums=0
prehead=ListNode(None)
prehead.next=head
cur=head
while(cur):
node_nums+=1
cur=cur.next
cur=prehead
for i in range(0,node_nums-n):
cur=cur.next
cur.next=cur.next.next
return prehead.next
双指针 一次遍历
class Solution:
def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
pre=ListNode(0)
pre.next=head
cur1=pre
cur2=pre
while(cur2.next):
if(n>0):
cur2=cur2.next
n-=1
else:
cur2=cur2.next
cur1=cur1.next
cur1.next=cur1.next.next
return pre.next
2020/9/10
24两两交换节点
class Solution:
def swapPairs(self, head: ListNode) -> ListNode:
pre=ListNode(-1)
pre.next=head
cur=pre
while(cur.next and cur.next.next):
#交换cur.next cur.next.next
p1=cur.next
p2=p1.next
p1.next=p2.next
p2.next=p1
cur.next=p2
cur=cur.next.next
return pre.next
445两数相加II
用栈保存两组数 用a1.pop a2.pop更方便写
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
result=None
a1,a2=[],[]
while(l1):
a1.append(l1.val)
l1=l1.next
while(l2):
a2.append(l2.val)
l2=l2.next
t=0 #进位 1或0
len1,len2=len(a1),len(a2)
if(len1<len2):
a1,a2=a2,a1
len1,len2=len2,len1
#a1长位 a2短位 或者位数相同
for i in range(-1,-1-len1,-1):
singleSum=a1[i]+a2[i]+t if -i<=len2 else a1[i]+t
temp=ListNode(singleSum%10)
temp.next=result
result=temp
# print(singleSum)
# print(result)
if(singleSum>=10):
t=1
else:
t=0
if(t==1):
temp=ListNode(1)
temp.next=result
result=temp
return result
234回文链表
class Solution:
def isPalindrome(self, head: ListNode) -> bool:
#两个字符串
a=[]
while(head):
a.append(head.val)
head=head.next
return a==a[::-1]
递归可以使得空间复杂度o(1) 或者切割成两半 反转一半 判断是否相等
725分割链表
class Solution:
def splitListToParts(self, root: ListNode, k: int) -> List[ListNode]:
#每份应当是num/k 前num%k个数应该+1 k>num时后面num-k份 null
#获取节点数
num=0
result=[]
cur=root
while(cur):
num+=1
cur=cur.next
#计算份数 平均节点数
singleNum=int(num/k)
moreNum=num%k
#给每一份 按照 节点数 得到结果
cur=root
for i in range(0,k):
iNum=singleNum+1 if i<moreNum else singleNum
if(iNum==0):
result.append(None)
else:
if(iNum>=2):
for j in range(0,iNum-1):
cur=cur.next
temp=cur.next
cur.next=None
result.append(root)
root=temp
cur=root
return result
class Solution:
def splitListToParts(self, root: ListNode, k: int) -> List[ListNode]:
#每份应当是num/k 前num%k个数应该+1 k>num时后面num-k份 null
#获取节点数
num=0
result=[]
cur=root
while(cur):
num+=1
cur=cur.next
#计算份数 平均节点数
singleNum=int(num/k)
moreNum=num%k
#给每一份 按照 节点数 得到结果
cur=root
for i in range(0,k):
iNum=singleNum+1 if i<moreNum else singleNum
if(iNum==0):
result.append(None)
else:
for j in range(0,iNum-1):
if(cur):
cur=cur.next
temp=cur.next
cur.next=None
result.append(root)
root=temp
cur=root
return result
328链表元素按奇偶聚集
遍历 是奇数点 连到h1 是偶数点 连到h2
h1的末尾连h2开头(cur1连cur2.next)
五个指针
class Solution:
def oddEvenList(self, head: ListNode) -> ListNode:
cur=head
h1,h2=ListNode(-1),ListNode(-1)
cur1,cur2=h1,h2
flag=True#奇数
while(cur):
temp=cur.next
cur.next=None
if(flag):
cur1.next=cur
cur1=cur1.next
else:
cur2.next=cur
cur2=cur2.next
flag=not flag
cur=temp
cur1.next=h2.next
return h1.next
下面是官方 4个指针
class Solution:
def oddEvenList(self, head: ListNode) -> ListNode:
while(head==None or head.next==None):
return head
cur1=head#奇:头head 尾cur1
h2=head.next#偶:头h2 尾cur2
cur2=h2
while(cur1.next and cur2.next):
cur1.next=cur2.next
cur2.next=cur2.next.next
cur1,cur2=cur1.next,cur2.next
cur1.next=h2
return head
2021/5/14
23. 合并K个升序链表
顺序合并很慢
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
p1=None
result=None
for p2 in lists:
result=self.merge2List(p1,p2)
p1=result
return result
def merge2List(self,l1,l2):
cur=ListNode(-1)
pre=cur
while(l1 and l2):
if(l1.val<=l2.val):
pre.next=l1
l1=l1.next
else:
pre.next=l2
l2=l2.next
pre=pre.next
if(l1):
pre.next=l1
if(l2):
pre.next=l2
return cur.next
这题关键是分治
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
return self.part(lists,0,len(lists)-1)
# 两两合并 返回l r位置合并后的一个链表
def part(self,lists,l,r):
# print('part:l{},r{}'.format(l,r))
if(l==r):
return lists[l]
if(l>r):
return None
mid=(l+r)//2
# 传参两个链表 返回排序合并的链表
return self.merge2List(self.part(lists,l,mid),self.part(lists,mid+1,r))
def merge2List(self,l1,l2):
cur=ListNode(-1)
pre=cur
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
if(l1):
cur.next=l1
if(l2):
cur.next=l2
return pre.next
61. 旋转链表
双指针 注意边界
# 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: ListNode, k: int) -> ListNode:
if((not head) or (k==0) or (head and not head.next)):
return head
step=1
tmp=head
while(tmp and tmp.next):
tmp=tmp.next
step+=1
k=k%step
if(k==0):
return head
# 找到倒数第k个位置
# [1,2,3,4,5] k=2,快慢指针找到3
# 快慢指针找到tmp tmp.next就是第K个
fast=ListNode(-1)
slow=ListNode(-1)
fast.next=head
slow.next=head
left=slow
# 快的先走k步 因为k<len 所以直接走就好了
for i in range(k):
fast=fast.next
while(fast and fast.next):
fast=fast.next
slow=slow.next
# fast是最后一个元素(非None)
# slow在3 fast在5
# print(slow) # 3-4-5
# print(fast) # 5
result=slow.next # slow不可能是最后一个
resultCur=slow.next
while(resultCur and resultCur.next):
resultCur=resultCur.next
# while(slow and slow.next):
# slow=slow.next
slow.next=None
resultCur.next=left.next
return result
看了题解 发现先连成环 再断开 会很方便 代码量少很多
# 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: ListNode, k: int) -> ListNode:
if((not head) or (k==0) or (head and not head.next)):
return head
# [1,2,3,4,5] k=2
step=1
cur=head
while(cur.next):
cur=cur.next
step+=1
k=k%step
# 此时cur在5
if(k==0):
return head
# 成环 找断开位置 找到3 (len-k)即可
cur.next=head
for i in range(step-k):
cur=cur.next
result=cur.next
cur.next=None
return result
2021/5/16
92. 反转链表 II
这题真心不太懂 按照自己的思路还可以
class Solution:
def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
if(left==right or not head or not head.next):
return head
dummy=ListNode(-1)
dummy.next=head
p1=dummy
# p1走到left前一个位置
for _ in range(left-1):
p1=p1.next
# p2=[left-----right-last]
p2=p1.next
p3=p2
# p3走到right位置
for _ in range(right-left+1):
p3=p3.next
# 现在 p1在left-1;p2是[left---right--last];p3是[last]
print(p1)
print(p2)
print(p3)
pre=p3 # pre是p2的头 后面就变成p2的尾 后面连p3
for _ in range(right-left+1):
nxt=p2.next
p2.next=pre
pre=p2
p2=nxt
p1.next=pre
# p2.next=p3
return dummy.next
官方题解方法一看不懂 关键是弄明白那个变量怎么修改链表 哪些变量是关联的 变量1变会不会影响变量2
2021/5/18
817. 链表组件
这题完全是题目描述不清晰。。
class Solution:
def numComponents(self, head: ListNode, nums: List[int]) -> int:
if(not head):
return 0
a=[] # 临时存储序列
nums=set(nums)
ret=0
while(head):
# 如果连续
if(head.val in nums):
a.append(head.val)
# print(a)
#idx=nums[idx::].index(head.val)+idx+1 # 更新开始搜索的下一个idx
#nums[idx-1]=-1 # 使用过的G位置数字置为-1
#nums.remove(head.val)
else:
# 说明断开连续了 重置
if(len(a)>0):
a=[]
ret+=1
head=head.next
ret=ret+1 if len(a)>0 else ret
return ret
143. 重排链表
直接用数组存储节点值
class Solution:
def reorderList(self, head: ListNode) -> None:
"""
Do not return anything, modify head in-place instead.
"""
if(not head or not head.next):
return
a=[]
cur=head
while(cur):
a.append(cur.val)
cur=cur.next
# [1,2,3,4,5]
left=0
right=len(a)-1
cur=head
while(left<=right):
if(left==right):
cur.next=ListNode(a[left])
else:
if(left>0):
cur.next=ListNode(a[left])
cur=cur.next
cur.next=ListNode(a[right])
cur=cur.next
left+=1
right-=1
为了节约空间,可以:
- 找中点
- 中点.next做右边;翻转右边
- 左右间隔相差
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reorderList(self, head: ListNode) -> None:
"""
Do not return anything, modify head in-place instead.
"""
if(not head or not head.next):
return
# 找Mid作为right
right=head
fast=head
while(fast and fast.next):
fast=fast.next.next
right=right.next
# 断开左右
l2=right.next
right.next=None
# 翻转右边
l2_reverse=None
while(l2):
nxt=l2.next
l2.next=l2_reverse
l2_reverse=l2
l2=nxt
# print(head)
# print(l2_reverse)
# 合并左右
cur=head # head一定大于等于l2_reverse
while(cur and l2_reverse):
nxt=l2_reverse.next
# 从l2中插入到l1中
l2_reverse.next=cur.next
cur.next=l2_reverse
l2_reverse=nxt
cur=cur.next.next
82. 删除排序链表中的重复元素 II
这题想明白了 就是写的很别扭
- 用dummy
- 用node.next判断值
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
if(not head or not head.next):
return head
# 快慢指针
dummy=ListNode(-1)
dummy.next=head
slow=dummy
fast=dummy.next
flag=False
while(fast and fast.next):
# 当fast相等于slow的下一个时
if(fast.next.val==slow.next.val):
flag=True
fast=fast.next
else:
# 不等的时候 falg=True说明fast的pre是相等的要删除
if(flag):
slow.next=fast.next
fast=fast.next
flag=False
else:
slow=slow.next
fast=fast.next
# 排除[2,1,1]情况 因为fast到了最后1的时候 fast.next=None 跳出循环
if(flag):
slow.next=fast.next
return dummy.next
还是题解简单
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
if(not head or not head.next):
return head
# 快慢指针
dummy=ListNode(-1)
dummy.next=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
2021/9/24
430. 扁平化多级双向链表
这题的核心是怎么更新cur的last
- 当cur.child时,last=cur.child.last
- 当cur.next时,lst=cur.next
刚开始一直不理解这个last,刚开始是写的注释掉的2写法,其实也可以但是会慢一点,主要就是搞清楚当node是第一个child时,其nxt中出现了child,那么node的tail怎么计算:
- 首先,node_nxt中出现一个child时,cur_node_tail = dfs(node_child)
- 核心在这,因为要遍历node这一链路,所以会继续更新 cur_node_tail;当node_child遍历完回来,node还有nxt时,还会往下遍历,如果nxt没有child,tail又会更新为nxt;所以就完成了tail的更新
class Solution:
def flatten(self, head: 'Node') -> 'Node':
if(not head):
return head
self.dfs(head)
return head
# head是child时 返回这条链路最后一个node
def dfs(self,head):
tail=head
cur=tail
while(cur):
nxt=cur.next
# cur有child时
if(cur.child):
# 1 更新head的tail
tail=self.dfs(cur.child)
print(f'cur:{cur.child.val},tail:{tail.val}')
# 更新child连接
cur.next=cur.child
cur.next.prev=cur
cur.child=None
# 更新tail.next
if(nxt):
tail.next=nxt
nxt.prev=tail
else:
tail=cur
# # 2 当前head是child节点
# # 2 所以当前head的tail 如果有child tail=dfs(child);紧接着如果nxt tail=nxt
# if(nxt):
# tail=nxt
cur=nxt
return tail
class Solution:
def flatten(self, head: 'Node') -> 'Node':
if(not head):
return head
self.dfs(head)
return head
# 将child这一链路修改 返回这一路的last
def dfs(self,node):
cur=node
tail=node
while(cur):
nxt=cur.next
if(cur.child):
child_t=self.dfs(cur.child)
# 第一步 cur-next
cur.next=cur.child
cur.child.prev=cur
cur.child=None
# 第二步 last-nxt
if(nxt):
child_t.next=nxt
nxt.prev=child_t
# 注意这个tail的更新位置
tail=child_t
else:
tail=cur
cur=nxt
return tail
114. 二叉树展开为链表
注意tail的位置
class Solution:
def flatten(self, root: TreeNode) -> None:
"""
Do not return anything, modify root in-place instead.
"""
if(not root):
return root
self.dfs(root)
return root
# 当root是left时 返回left链路的最后一个node
def dfs(self,root):
cur=root
tail=root
while(cur):
nxt=cur.right
if(cur.left):
# left节点的链路最后一个node
left_tail=self.dfs(cur.left)
# print(f'cur{cur.val},left_tail{left_tail.val},right{nxt.val}')
left_tail.right=nxt
cur.right=cur.left
cur.left=None
tail=left_tail
# right存在时
cur=nxt
if(nxt):
tail=nxt
return tail