LeetCode第 393 场周赛

第三题3116. 单面值组合的第 K 小金额

题目大意: 给定一个整数数组coins表示不同面额的硬币,另给定一个整数k。你有无限量的每种面额的硬币,但是,你不能组合使用不同面额的硬币。要求返回使用这些硬币能制造的第kth小金额。

实现思路:

  • 首先,对于给定的硬币数组,我们需要求出它们的所有可能的组合方式。
  • 使用位运算来枚举所有的组合方式,对于数组中的每个硬币,分别考虑选取和不选取两种情况,通过位运算将这两种情况枚举出来。
  • 对于每种组合方式,计算其对应的最小公倍数(LCM)作为该组合的金额。
  • 根据组合的奇偶性,将金额的正负号记录下来,并存储在列表ls中。
  • 利用二分查找来求解第kth小的金额,通过不断调整左右边界,直到找到满足条件的金额。
  • 返回最终找到的金额作为结果。

这种方法利用了位运算和二分查找的思想,可以在较短的时间内求解出结果。

class Solution:
    def findKthSmallest(self, coins: List[int], k: int) -> int:
        n = len(coins)
        ls = []
        for i in range(1, 1<<n):
            Lcm = 1
            for j, x in enumerate(coins):
                if i>>j & 1:
                    Lcm = lcm(Lcm, x)
            ls.append((1, Lcm)) if i.bit_count()&1 else ls.append((-1, Lcm))
        l, r = 1, int(5e10)
        while l<r:
            mid = l+r>>1
            cnt = 0
            for sign, val in ls:
                cnt += sign*(mid//val)
            if cnt>=k:
                r = mid
            else:
                l = mid+1
        return l

第四题3117. 划分数组得到最小的值之和

题目大意: 给定两个数组nums和andValues,长度分别为n和m。数组的值等于该数组的最后一个元素。需要将nums划分为m个不相交的连续子数组,对于第ith个子数组[li, ri],子数组元素的按位AND运算结果等于andValues[i]。返回将nums划分为m个子数组所能得到的可能的最小子数组值之和。如果无法完成这样的划分,则返回-1。

实现思路:

  • 使用动态规划来解决此问题,具体来说,可以采用递归加记忆化搜索的方法。
  • 定义dfs函数用于递归求解,其中i表示当前处理到nums的第i个元素,j表示当前处理到andValues的第j个元素,k表示当前子数组的按位AND运算结果。
  • 在dfs函数中,首先进行边界条件的判断,如果i等于n,表示nums已经处理完毕,则返回0(如果j等于m)或者正无穷(如果j不等于m)。
  • 然后,对当前nums[i]进行按位AND运算,并更新k的值。如果更新后的k小于andValues[j],则返回正无穷。
  • 如果更新后的k等于andValues[j],则递归调用dfs函数继续处理下一个元素,同时更新i和j,并将k重置为-1。递归调用的结果加上nums[i]的值即为当前划分情况的子数组值之和。
  • 最后,返回所有划分情况中的最小值作为答案,如果答案为正无穷,则返回-1。

这种方法利用了递归和记忆化搜索的思想,避免了重复计算,提高了效率。

class Solution:
    def minimumValueSum(self, nums: List[int], andValues: List[int]) -> int:
        n = len(nums)
        m = len(andValues)

        @cache
        def dfs(i, j, k):
            if i==n:
                return 0 if j==m else inf
            if j==m:
                return inf
            k&=nums[i]
            if k<andValues[j]:
                return inf
            res = dfs(i+1, j, k)
            if k==andValues[j]:
                res = min(res, dfs(i+1, j+1, -1)+nums[i])
            return res
        ans = dfs(0, 0, -1)
        return ans if ans<inf else -1