Questions related to "K" in the interview algorithm and data structure

table of Contents

One, linked list

Second, the binary tree

Three, the prefix and

Four, dynamic planning

Five, heap sort

Six, array


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

Sum is a sub-array of K

输入: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

K number

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 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

Guess you like

Origin blog.csdn.net/Matrix_cc/article/details/106636321