面试算法和数据结构中那些和 “K” 相关的题目

目录

一、链表

二、二叉树

三、前缀和

四、动态规划

五、堆排序


本文会列举几道比较常见的题目中带有 “K” 的问题,有的问题在我的另一篇博客里做了详细的解释,所以这篇文章里我就不做太多解释

一、链表

1、返回倒数第 k 个节点

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

先让快指针走k步,然后再同时走,快指针走到结尾时慢指针就走到第k个节点了

2、合并 K 个排序链表

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

使用二分法来两两合并链表

二、二叉树

二叉搜索树的第 k 大节点

输入: root = [3,1,4,null,2], k = 1
   3
  / \
 1   4
  \
   2
输出: 4

递归版写法:

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  

迭代版写法:

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

三、前缀和

和为 K 的子数组

输入:nums = [1,1,1], k = 2
输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。

第一眼看到题,我还以为是和 组合总和 这道题一样

输入: candidates = [2,3,6,7], target = 7,
所求解集为:
[
  [7],
  [2,2,3]
]

于是上来就套用回溯模板,当然最后答案是错的,看了解析发现是用前缀和。

什么是前缀和呢?其实就是数组当前项的总和

面试算法和数据结构中那些和 “K” 相关的题目_第1张图片

字典的为前缀和,即从第 0 项到当前项的总和,为这个 前缀和 值出现了几次
遍历 nums 之前,我们预置边界情况 (即之前提到的 prefixSum [-1] = 0):map 初始放入 0:1 键值对,即预设已经出现 1 次为 0 的前缀和

遍历 nums 的每一项,求当前项的前缀和,存入 map 中

之前没有存过,则存入,初始值为 1
之前存过,则对应值 +1,即出现次数 +1
边存边查看 map ,如果 map 中已存在 key 为 当前前缀和 - k

说明存在 【之前求出的前缀和】,它的值满足 【当前前缀和】-【之前求出的前缀和】 == k
把 【之前求出的前缀和】 出现的次数,累加给 count 计数器

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

四、动态规划

第 k 个数

这道题实际上是和 丑数 这道题类似的,这里使用的是动态规划的做法,当然也可以用堆的做法,这里就不介绍堆的用法

这是使用三指针的dp做法

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]

五、堆排序

堆排序这章的内容在我的博客 https://blog.csdn.net/Matrix_cc/article/details/106606612 里已有介绍,这里就不介绍了

参考:

leetcode题解中的一些解释

你可能感兴趣的:(数据结构与算法)