table of Contents
This article will list a few more common questions with "K" in the title. Some questions are explained in detail in another blog of mine, so I won't explain too much in this article.
One, linked list
1. Return the kth node from the bottom
输入: 1->2->3->4->5 和 k = 2 输出: 4
class Solution:
def kthToLast(self, head: ListNode, k: int) -> int:
fast = head
slow = head
while k!=0:
fast = fast.next
k-=1
while fast:
fast = fast.next
slow = slow.next
return slow.val
Let the fast pointer go k steps first, and then go at the same time. When the fast pointer reaches the end, the slow pointer will go to the kth node.
2. Merge K sorted linked lists
输入: [ 1->4->5, 1->3->4, 2->6 ] 输出: 1->1->2->3->4->4->5->6
class Solution:
def mergeKLists(self, lists: List[ListNode]) -> ListNode:
if not lists:return None
return self.helper(lists,0,len(lists)-1)
def helper(self,lists,l,r):
if l==r:
return lists[l]
# if l>r:
# return None
mid = l + (r - l) // 2
l1 = self.helper(lists,l,mid)
l2 = self.helper(lists,mid+1,r)
return self.mergeTwoList(l1, l2)
def mergeTwoList(self,A,B):
if not A or not B:
return B if not A else A
cur = ListNode(-1)
tmp = cur
while A and B:
if A.val<=B.val:
tmp.next = A
A = A.next
else:
tmp.next = B
B = B.next
tmp = tmp.next
tmp.next = A if A else B
return cur.next
Use dichotomy to merge linked lists in pairs
3. A set of K flip linked lists
class Solution:
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
if not head or not head.next:
return head
tail = head
for i in range(k):
if not tail:
return head
tail = tail.next
newHead = self.reverse(head,tail)
head.next = self.reverseKGroup(tail,k)
return newHead
def reverse(self,start,end):
pre = None
while start!=end:
node = start.next
start.next = pre
pre = start
start = node
return pre
Using the recursive method, k inverted once, but not enough to invert k. You can also use the stack method to push k nodes into the stack, and then pop them to add to the result list.
class Solution:
def reverseKGroup(self, head: ListNode, k: int) -> ListNode:
dummy = ListNode(0)
p = dummy
while True:
count = k
stack = []
tmp = head
while count and tmp:
stack.append(tmp)
tmp = tmp.next
count -= 1
# 注意,目前tmp所在k+1位置
# 说明剩下的链表不够k个,跳出循环
if count :
p.next = head
break
# 翻转操作
while stack:
p.next = stack.pop()
p = p.next
#与剩下链表连接起来
p.next = tmp
head = tmp
return dummy.next
Second, the binary tree
The k-th largest node of the binary search tree
输入: root = [3,1,4,null,2], k = 1 3 / \ 1 4 \ 2 输出: 4
Recursive version:
class Solution:
count = 0
res = 0
def kthLargest(self, root: TreeNode, k: int) -> int:
return self.helper(root,k)
def helper(self,root,k):
if not root:
return
self.helper(root.right,k)
self.count +=1
if k==self.count:
self.res = root.val
self.helper(root.left,k)
return self.res
Iterative version:
class Solution:
def kthLargest(self, root: TreeNode, k: int) -> int:
if not root:
return None
stack = []
node = root
while node or len(stack)>0:
while node:
stack.append(node)
node = node.right
node = stack.pop()
if k==1:
self.res = node.val
k-=1
node = node.left
return self.res
Three, the prefix and
输入:nums = [1,1,1], k = 2 输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。
When I first saw the question, I thought it was the same as the combined sum question.
输入: candidates = [2,3,6,7], target = 7, 所求解集为: [ [7], [2,2,3] ]
So I applied the backtracking template, of course, the final answer was wrong. After reading the analysis, I found that the prefix sum was used.
What is the prefix sum? Is actually the sum of the current items in the array
Dictionary key prefix and, i.e., from 0 to the sum of the current item, the value of the emergence of several values for the prefix and
before traversing the nums, we preset boundaries (i.e. before mentioned prefixSum [-1] = 0 ): The map is initially put into a 0:1 key-value pair, that is, the prefix sum of 0 is preset to appear once.
Traverse each item of nums, find the prefix sum of the current item, and store it in the map
Had not previously exist, is stored, an initial value is
stored through before, the corresponding value of +1, i.e. the number of occurrences +1
side edge view map memory, if the key already exists in the map as the current prefix and - k
Explain that there is [prefix sum calculated before], and its value satisfies [current prefix sum]-[prefix sum calculated before] == k
accumulate the number of occurrences of [prefix sum calculated before] to the count counter
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
if not nums:
return 0
dic = dict()
dic[0] = 1
acc = 0
count = 0
for num in nums:
acc += num
if (acc-k) in dic:
count+=dic[acc-k]
if acc not in dic:
dic[acc] = 1
else:
dic[acc] += 1
return count
Four, dynamic planning
This question is actually similar to the ugly number question. The dynamic programming method is used here. Of course, the heap method can also be used. The heap usage is not introduced here.
This is the dp approach using three pointers
class Solution:
def getKthMagicNumber(self, k: int) -> int:
a,b,c = 0,0,0
dp = [1]*k
for i in range(1,k):
n1,n2,n3 = dp[a]*3,dp[b]*5,dp[c]*7
dp[i] = min(n1,n2,n3)
if dp[i]==n1:
a+=1
if dp[i]==n2:
b+=1
if dp[i]==n3:
c+=1
return dp[-1]
Five, heap sort
The content of this chapter on heap sorting has been introduced in my blog https://blog.csdn.net/Matrix_cc/article/details/106606612 , so I won’t introduce it here.
Six, array
Combine k ordered arrays
Add the first element of each array to the heap, build a small top heap, then pop the top element of the heap and add it to the res array, and then add the next element of the array corresponding to the popped element to the heap, and the loop is complete
L is the number of arrays, N is the number of elements in the array
- Time complexity: Since each element needs to be read once, that is, the maximum number of times is L*N, the complexity of inserting each element into the smallest heap is O (logL), that is, the total complexity is O (L*NlogL )
- The space complexity is: maintain the minimum heap size, which is O (L)
import heapq
from collections import deque
def list_merge(*lists):
# 入参判断, 这里直接pass
# 将所有链表转化为deque,方便使用popleft获取链表的最左元素及根据索引返回该索引对应的剩余链表
queues = [queue for queue in map(deque, lists)]
heap = []
# 初始化链表,该链表中的元素为元组, 各个链表的第一个元素及链表所在索引
for i, lst in enumerate(queues):
heap.append((lst.popleft(), i))
# 将链表转换成最小堆
heapq.heapify(heap)
# 链表: 用于存放每次获取的堆顶层元素
result = []
while heap:
# 将堆顶层元素出堆
value, index = heapq.heappop(heap)
# 将顶层元素追加
result.append(value)
# 根据索引获取对应链表的剩余元素
if queues[index]:
# 如果存在下一个元素,则将该元素及索引入堆
heapq.heappush(heap, (queues[index].popleft(), index))
return result
print(list_merge(*[[4, 8, 20], [100, 200, 350, 370], [5, 8, 350, 500, 1000]]))
reference:
Some explanations in Leetcode solution