2024-12-01:单面值组合的第 K 小金额。用go语言,给定一个整数数组 coins,表示不同面值的硬币,同时给出一个整数

举报
福大大架构师每日一题 发表于 2024/12/01 20:24:16 2024/12/01
【摘要】 2024-12-01:单面值组合的第 K 小金额。用go语言,给定一个整数数组 coins,表示不同面值的硬币,同时给出一个整数 k。你可以使用任意数量的这些硬币,但不能将不同面值的硬币组合在一起。请返回可以用这些硬币构成的第 k 个最小金额。1 <= coins.length <= 15。1 <= coins[i] <= 25。1<=k<=2∗1091 <= k <= 2 * 10^91<...

2024-12-01:单面值组合的第 K 小金额。用go语言,给定一个整数数组 coins,表示不同面值的硬币,同时给出一个整数 k。你可以使用任意数量的这些硬币,但不能将不同面值的硬币组合在一起。请返回可以用这些硬币构成的第 k 个最小金额。

1 <= coins.length <= 15。

1 <= coins[i] <= 25。

1<=k<=21091 <= k <= 2 * 10^9

输入:coins = [5,2], k = 7。

输出:12。

解释:给定的硬币可以制造以下金额:

5元硬币产生5的倍数:5, 10, 15, 20等。

2元硬币产生2的倍数:2, 4, 6, 8, 10, 12等。

所有硬币合起来可以产生:2, 4, 5, 6, 8, 10, 12, 14, 15等,12是第7个数。

答案2024-12-01:

chatgpt

题目来自leetcode3116。

大体步骤如下:

1.对给定的硬币面值数组 coins 进行排序,以便后续处理。

2.创建一个空数组 a 用于存放不同面值的硬币。

3.遍历排序后的硬币数组,对于每一个硬币 x:

  • 遍历数组 a 中的每个元素 y,检查是否 x 能整除 y,如果可以,则跳过该硬币 x。

  • 如果 x 不能整除任何已选中的硬币,则将 x 加入数组 a。

4.计算数组 a 的所有子集的最小公倍数,并根据每个子集包含硬币的数量对最小公倍数的正负号进行调整。

5.使用二进制位运算构建所有子集的最小公倍数。

6.使用二进制计数方法判断对应子集的硬币数量是否大于等于 k。

7.输出第 k 个最小金额。

总体而言,这个解决方案涉及对硬币面值进行排序、计算最小公倍数、二进制位运算等操作。时间复杂度取决于硬币面值数组的长度和 k,为 O(2^n * n + n^2 * log(n)),其中 n 为硬币数量。

额外空间复杂度为 O(2^n)。

Go完整代码如下:

package main

import (
	"fmt"
	"slices"
	"sort"
	"math/bits"
)

func findKthSmallest(coins []int, k int) int64 {
	slices.Sort(coins)
	a := coins[:0]
next:
	for _, x := range coins {
		for _, y := range a {
			if x%y == 0 {
				continue next
			}
		}
		a = append(a, x)
	}

	subsetLcm := make([]int, 1<<len(a))
	subsetLcm[0] = 1
	for i, x := range a {
		bit := 1 << i
		for mask, l := range subsetLcm[:bit] {
			subsetLcm[bit|mask] = lcm(l, x)
		}
	}
	for i := range subsetLcm {
		if bits.OnesCount(uint(i))%2 == 0 {
			subsetLcm[i] *= -1
		}
	}

	ans := sort.Search(a[0]*k, func(m int) bool {
		cnt := 0
		for _, l := range subsetLcm[1:] {
			cnt += m / l
		}
		return cnt >= k
	})
	return int64(ans)
}

func gcd(a, b int) int {
	for a != 0 {
		a, b = b%a, a
	}
	return b
}

func lcm(a, b int) int {
	return a / gcd(a, b) * b
}

func main() {
	coins := []int{5,2}
	k := 7
	fmt.Println(findKthSmallest(coins,k))
}

在这里插入图片描述

Rust完整代码如下:

use std::cmp::Ordering;

fn find_kth_smallest(coins: &[i32], k: i32) -> i64 {
    let mut sorted_coins = coins.to_vec();
    sorted_coins.sort_unstable();

    let mut filtered_coins = Vec::new();
    'next: for &x in &sorted_coins {
        for &y in &filtered_coins {
            if x % y == 0 {
                continue 'next;
            }
        }
        filtered_coins.push(x);
    }

    let n = filtered_coins.len();
    let subset_lcm_size = 1 << n;
    let mut subset_lcm = vec![1; subset_lcm_size];

    for (i, &x) in filtered_coins.iter().enumerate() {
        let bit = 1 << i;
        for mask in 0..bit {
            subset_lcm[bit | mask] = lcm(subset_lcm[mask], x);
        }
    }

    for i in 0..subset_lcm_size {
        if i.count_ones() % 2 == 0 {
            subset_lcm[i] *= -1;
        }
    }

    let max_search_value = filtered_coins[0] * k;
    let mut low = 1;
    let mut high = max_search_value;

    while low < high {
        let mid = (low + high) / 2;
        let mut cnt = 0;

        for &l in &subset_lcm[1..] {
            cnt += mid / l;
        }

        if cnt >= k {
            high = mid; // If we have enough counts, we try smaller value
        } else {
            low = mid + 1; // If not enough, we go higher
        }
    }

    low as i64
}

fn gcd(a: i32, b: i32) -> i32 {
    let mut a = a;
    let mut b = b;
    while a != 0 {
        let temp = b;
        b = a;
        a = temp % a;
    }
    b
}

fn lcm(a: i32, b: i32) -> i32 {
    a / gcd(a, b) * b
}

fn main() {
    let coins = vec![5, 2];
    let k = 7;
    println!("{}", find_kth_smallest(&coins, k));
}

在这里插入图片描述

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。