自己刷题的一个小记录,难度从easy --> hard,持续更新中。若有更好的方法,欢迎评论区讨论呀。
876. 返回单链表的中间节点。如果有两个中间节点,返回第二个。
两种思路,
第一种是先遍历一遍,记录长度后,再遍历到一半。时间复杂度O(n)
第二种是用两个指针,一快一慢,快指针每次走两步,慢指针每次走一步,当快指针走到链表最后时,慢指针所指的就是中间节点。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
'''
先遍历一遍,记录长度,再遍历一半。
class Solution:
def middleNode(self, head: ListNode) -> ListNode:
if head.next ==None:
return head
length = 1
phead = head
while head.next !=None:
length +=1
head = head.next
mid = length//2
for i in range(mid):
phead = phead.next
return phead
'''
# 直接快慢指针,快的到头以后,慢的就是中间值
class Solution:
def middleNode(self, head: ListNode) -> ListNode:
if head.next ==None:
return head
fast = head
slow = head
while fast and fast.next:
fast = fast.next.next
slow = slow.next
return slow
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:
# 递归版本,一直往后遍历,每次建立一个反转链接
return self.reverse(head,None)
def reverse(self, current, prev):
if current == None:
return prev
nxt = current.next
current.next = prev
prev = current
current = nxt
return self.reverse(current, prev)
'''
class Solution:
def reverseList(self, head: ListNode) -> ListNode:
# 迭代版本
return self.reverse(head,None)
def reverse(self, current, prev):
if current == None:
return prev
while current!=None:
nxt = current.next
current.next = prev
prev = current
current = nxt
return prev
237. 删除单链表中的某一节点
这题要注意的是,并没有给出完整的链表,函数参数中只是给了要删除的节点。
但由于是单链表,没法获取被删除节点前的节点,所以将被删除节点的值改为后面一个节点的值,然后删除后面一个节点即可。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteNode(self, node):
"""
:type node: ListNode
:rtype: void Do not return anything, modify node in-place instead.
"""
# 没有给完整的单链表,只是给了要删除的节点!没有head!
node.val = node.next.val
node.next = node.next.next
21. 合并两个已排序的单链表
用两个指针分别遍历两个链表。遇到较小的一个,就加到合并列表后面,并指针后移。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
newlist = ListNode(0)
tmp = newlist
while l1!=None and l2!=None:
if l1.val<l2.val:
tmp.next = l1
l1 = l1.next
else:
tmp.next = l2
l2 = l2.next
tmp = tmp.next
if l1!=None:
while l1!=None:
tmp.next = l1
l1 = l1.next
tmp = tmp.next
if l2!=None:
while l2!=None:
tmp.next = l2
l2 = l2.next
tmp = tmp.next
return newlist.next
83.给定一个排序后的单链表,删除其中的重复节点,保证每个节点只出现一次。
思路:遇到重复的节点,就往后遍历,直到节点不重复即可。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def deleteDuplicates(self, head: ListNode) -> ListNode:
tmp = head
while tmp!=None:
nxt = tmp.next
while nxt!=None and nxt.val== tmp.val:
nxt = nxt.next
tmp.next = nxt
tmp = nxt
return head
141. 判断单链表是否有环
思路:用快慢指针,如果有环,那么两个指针一定会相遇。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def hasCycle(self, head):
"""
:type head: ListNode
:rtype: bool
"""
# 快慢指针,如果有环,那么总归会相遇
if head==None or head.next==None:
return False
fast = head.next
slow = head
flag = 0
while fast!=slow:
if fast==None or fast.next==None:
return False
fast = fast.next.next
slow = slow.next
return True
234.判断一个单链表是否是回文的。
思路1: 笨方法,遍历链表,将链表的节点值存储在数组中,再分别比较数组的头尾。
思路2: 先遍历一遍列表,记录长度。然后将链表分成两半,前面一半进行反转,然后与后面一半比较是否完全相等。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
'''另外用一个数组将链表节点的值存下来,空间复杂度O(N)'''
'''
def isPalindrome(self, head):
vals = []
while head:
vals += head.val,
head = head.next
return vals == vals[::-1]
'''
def isPalindrome(self, head: ListNode) -> bool:
# 先遍历一遍链表,记录链表长度。
# 然后从中间将链表切成前后两半,并把前面一半进行反转,然后与后面一半进行比较
if head==None or head.next==None:
return True
node = head
count = 0
while node!=None:
count+=1
node=node.next
node = head
prev = None
for i in range(count//2):
nxt = node.next
node.next = prev
prev = node
node = nxt
if count%2==0:
h2 = node
else:
h2 = node.next
h1 = prev
while h1 and h2:
if h1.val!=h2.val:
return False
h1 = h1.next
h2 = h2.next
return True
203. 给定一个链表和一个值val,将链表中值为val的节点都删除。
注意考虑头部节点需要删除的情况即可。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def removeElements(self, head: ListNode, val: int) -> ListNode:
if head==None:
return head
if head.next==None:
if head.val == val:
return None
else:
return head
while head!=None and head.val==val:
head=head.next
node = head
while node!=None:
if node.next!=None and node.next.val ==val:
node.next = node.next.next
else:
node = node.next
return head
160. 找两个链表的交点。
思路1: 先分别遍历一遍两个链表,记录他们的长度l1和l2,让长的那个链表先走|l1-l2|步,再同时走,就能走到交点处。
思路2: 更简洁的一个方法,两个链表同时从头节点走,其中一个走到头后,redirect到另一个链表的头节点。这样就能找到交点。
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
'''
先分别记录两个链表的长度,然后让长的那个先走“差值”步,再同时走,就能一起走到交点处
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
if headA == None or headB==None:
return None
node1 = headA
node2 = headB
length1, length2 = 0, 0
while node1!=None:
length1+=1
node1 = node1.next
while node2!=None:
length2+=1
node2 = node2.next
if length1>length2:
for i in range(length1-length2):
headA = headA.next
else:
for i in range(length2-length1):
headB = headB.next
while headA!=headB:
headA = headA.next
headB = headB.next
return headA
'''
'''
更简洁的一个方法,两个链表同时从头节点走,其中一个走到头后,redirect到另一个链表的头节点。这样就能找到交点'''
class Solution(object):
def getIntersectionNode(self, headA, headB):
"""
:type head1, head1: ListNode
:rtype: ListNode
"""
if headA == None or headB==None:
return None
node1 = headA
node2 = headB
while node1!=node2:
node1 = headB if node1==None else node1.next
node2 = headA if node2==None else node2.next
return node1
707. 实现一个单链表类,包括一系列添加节点、删除节点的函数。
class listNode:
def __init__(self, val):
self.val = val
self.next = None
class MyLinkedList(object):
def __init__(self):
"""
Initialize your data structure here.
"""
self.head = None
self.size = 0
def get(self, index):
"""
Get the value of the index-th node in the linked list. If the index is invalid, return -1.
:type index: int
:rtype: int
"""
if index<0 or index>=self.size:
return -1
if self.head is None:
return -1
node = self.head
for i in range(index):
node = node.next
return node.val
def addAtHead(self, val):
"""
Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list.
:type val: int
:rtype: None
"""
newHead = listNode(val)
newHead.next = self.head
self.head = newHead
self.size +=1
def addAtTail(self, val):
"""
Append a node of value val to the last element of the linked list.
:type val: int
:rtype: None
"""
newnode = listNode(val)
node = self.head
if node ==None:
self.head = newnode
else:
while node.next!=None:
node = node.next
node.next = newnode
self.size+=1
def addAtIndex(self, index, val):
"""
Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted.
:type index: int
:type val: int
:rtype: None
"""
if index>0 and index <= self.size:
node = self.head
for i in range(index-1):
node = node.next
newnode = listNode(val)
newnode.next = node.next
node.next = newnode
self.size +=1
elif index<=0:
self.addAtHead(val)
def deleteAtIndex(self, index):
"""
Delete the index-th node in the linked list, if the index is valid.
:type index: int
:rtype: None
"""
if index>0 and index<self.size:
node = self.head
for i in range(index-1):
node = node.next
node.next = node.next.next
self.size -=1
elif index==0:
self.head = self.head.next
self.size -=1
# Your MyLinkedList object will be instantiated and called as such:
# obj = MyLinkedList()
# param_1 = obj.get(index)
# obj.addAtHead(val)
# obj.addAtTail(val)
# obj.addAtIndex(index,val)
# obj.deleteAtIndex(index)
1019.给定一个单链表,返回一个数组,数组中第i个元素是链表中第i个节点的next greater值,即最近的比第i个节点值大的节点值。
example:
Input: [1,7,5,1,9,2,5,1]
Output: [7,9,9,9,0,5,0,0]
思路:用一个栈来存储‘还没有遇到next greater的节点’,每次当前节点与栈顶进行比较。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
'''
用一个stack来存储‘还没有遇到next greater的节点’,每次当前节点与栈顶进行比较 '''
class Solution:
def nextLargerNodes(self, head: ListNode) -> List[int]:
if head==None:
return None
elif head.next == None:
return [0]
ans = []
stack = []
pos = -1
while head:
pos +=1
ans.append(0)
# 把栈顶元素和当前节点进行比较
while stack and stack[-1][1]<head.val:
# 小的话,就把栈顶元素弹出,并且写到ans数组中
# 直到栈为空
index, _ = stack.pop()
ans[index] = head.val
stack.append((pos,head.val))
head = head.next
return ans
817. 单链表的组成部分
给定一个单链表和一个数组,数组是单链表节点值的子集。返回一个number,代表数组中的值在单链表中分为几个相连部分。
example:
输入:
head: 0->1->2->3
G = [0, 1, 3]
输出: 2
Explanation: 0 and 1 are connected, so [0, 1] and [3] are the two connected components.
思路:遍历单链表的节点,如果节点值在数组中出现,那么往后遍历,直到不出现则出现断点,就表示number+=1。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
'''
def numComponents(self, head: ListNode, G: List[int]) -> int:
# 遍历单链表,然后看连续的链表部分是否出现在list中
node = head
count = 0
while node!=None:
if node.val in G:
while node!=None and node.val in G:
node = node.next
count+=1
if node!=None:
node = node.next
return count
'''
#更简洁的写法
def numComponents(self, head, G):
setG = set(G)
res = 0
while head:
if head.val in setG and (head.next == None or head.next.val not in setG):
res += 1
head = head.next
return res
445. 给定两个单链表,分别表示两个整数,返回两个整数的和。且题目要求不能反转链表。
example:
Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 8 -> 0 -> 7
思路:由于不能反转链表,那么我想到的只能是把数存下来,相加后再构造新的链表。有更好的方法会再更新。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def addTwoNumbers(self, l1: ListNode, l2: ListNode) -> ListNode:
# 不能反转链表
# 第一个方法,将链表遍历后,得到数字,相加后再构造一个链表
num1, num2 = 0,0
while l1!=None:
num1 = num1*10 + l1.val
l1 = l1.next
while l2!=None:
num2 = num2*10 + l2.val
l2 = l2.next
x = num1+num2
head = ListNode(0)
if x == 0: return head
while x:
v, x = x%10, x//10
head.next, head.next.next = ListNode(v), head.next
return head.next
328. 给定一个单链表,把链表中的奇数节点都放到前面,偶数节点放到后面,且不改变奇数之间和偶数之间的相对顺序。
思路:与86题相似,建立两个空节点,然后奇数偶数分别连到后面,再合并链表。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def oddEvenList(self, head):
dummy1 = odd = ListNode(0)
dummy2 = even = ListNode(0)
while head:
odd.next = head
even.next = head.next
odd = odd.next
even = even.next
head = head.next.next if even else None
odd.next = dummy2.next
return dummy1.next
725. 给定一个单链表,和一个数字k,要求把链表分为k个部分,且每个部分的元素个数相差不超过1。
example:
Input: root = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], k = 3
Output: [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
思路:首先考虑k比链表长度小的情况,直接分割即可。其他的,先遍历链表,记录长度len,len//k表示每个组元素的最少个数,len%k=num表示多的元素个数,分别在前num个块中加上1个元素。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def splitListToParts(self, root: ListNode, k: int) -> List[ListNode]:
# 先记录链表长度length,然后length/k,余数yushu表示多的,那么在前yushu个段加1个
node = root
length = 0
while node!=None:
length+=1
node = node.next
ans =[]
node = root
shang = length//k
yushu = length%k
for i in range(k):
head = ListNode(0)
s = head
if i<yushu:
for j in range(shang+1):
head.next = node
node = node.next
head = head.next
else:
for j in range(shang):
head.next = node
node = node.next
head = head.next
head.next = None
ans.append(s.next)
return ans
24. 交换链表中每两个相邻的节点。
example:
Given 1->2->3->4, you should return the list as 2->1->4->3.
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def swapPairs(self, head):
pre, pre.next = self, head
while pre.next and pre.next.next:
a = pre.next
b = a.next
pre.next, b.next, a.next = b, a, b.next
pre = a
return self.next
430. 把一个层级的,含有子节点的双向链表进行flatten,表示成一个新的双向链表。
example:
思路:用一个栈来存储4、9节点。即遇到有子节点的节点,将后面的节点入栈。遍历到最后一层的最后节点后,开始出栈,将节点加到后面,直到栈为空。
"""
# Definition for a Node.
class Node:
def __init__(self, val, prev, next, child):
self.val = val
self.prev = prev
self.next = next
self.child = child
"""
class Solution:
# 每次遇到有child节点的节点,就把next入栈。遍历到最后之后,再从栈里pop出节点加在后面
def flatten(self, head: 'Node') -> 'Node':
stack = []
node = head
prev = node
while node:
if node.child!=None:
if node.next:
stack.append(node.next)
node.child.prev = node
node.next = node.child
node.child = None
if not node.next and len(stack):
curr = stack.pop()
curr.prev = node
node.next = curr
node = node.next
return head
1171. 给定一个单链表,删除其中和为0的部分。
example:
Input: head = [1,2,-3,3,1]
Output: [3,1]
Note: The answer [1,2,1] would also be accepted.
思路:用一个字典来存储当前的累加值,如果累加值出现重复,那么说明有和为0的部分存在。把这部分节点删去,同时注意删去字典中存储的这部分节点累加值。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def removeZeroSumSublists(self, head: ListNode) -> ListNode:
# 用一个值来存当前的累加和
# 再用一个字典来存累加和出现的次数
node = head
sums, zidian = 0, {}
while node:
sums += node.val
if sums ==0:
head = node.next
zidian.clear()
else:
if sums not in zidian:
zidian[sums] = node
else:
#zidian[sums].next = node.next
pre = zidian[sums]
sums2 = sums + pre.next.val
while sums2 != sums:
curr = zidian[sums2]
del zidian[sums2]
sums2 += curr.next.val
pre.next = node.next
#zidian[sums] = None
node = node.next
return head
86. 给定一个单链表和一个值x,把链表中小于x的节点放在前面,大于x的节点放到后面。
example:
Input: head = 1->4->3->2->5->2, x = 3
Output: 1->2->2->4->3->5
思路:和奇偶划分类似,构造两个新的节点。
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def partition(self, head: ListNode, x: int) -> ListNode:
l1 = ListNode(0)
l2 = ListNode(0)
s1,s2 = l1, l2
while head:
if head.val<x:
l1.next = head
l1 = l1.next
else:
l2.next = head
l2 = l2.next
head = head.next
l2.next = None
l1.next = s2.next
return s1.next