2023-09-13:用go语言,给定一个整数数组 nums 和一个正整数 k, 找出是否有可能把这个数组分成 k 个非空子集,其总和都相等。 输入: nums = [4, 3, 2, 3, 5,
2023-09-13:用go语言,给定一个整数数组 nums 和一个正整数 k,
找出是否有可能把这个数组分成 k 个非空子集,其总和都相等。
输入: nums = [4, 3, 2, 3, 5, 2, 1], k = 4。
输出: True。
来自左程云。
答案2023-09-13:
第一种算法(canPartitionKSubsets1)使用动态规划的思想,具体过程如下:
1.计算数组nums的总和sum。如果sum不能被k整除,则直接返回false。
2.调用process1函数,传入数组nums、status初始值为0、sum初始值为0、sets初始值为0、limit为sum/k、k和一个空的dp map。
3.在process1函数中,首先检查dp map,如果已经计算过该状态,则直接返回dp[status]。
4.如果sets等于k,表示已经找到k个非空子集,返回1。
5.遍历数组nums,对于每个数字nums[i],判断该数字是否可以加入到当前的子集中。
6.如果当前子集的和加上nums[i]等于limit,则将状态status的第i位设置为1,sum重置为0,sets加1,继续递归调用process1函数。
7.如果当前子集的和加上nums[i]小于limit,则将状态status的第i位设置为1,sum加上nums[i],sets保持不变,继续递归调用process1函数。
8.如果递归调用的结果为1,则表示找到了满足条件的分组,设置ans为1,并跳出循环。
9.更新dp map,将状态status对应的结果ans存入dp[status],并返回ans。
第二种算法(canPartitionKSubsets2)使用回溯的思想,具体过程如下:
1.计算数组nums的总和sum。如果sum不能被k整除,则直接返回false。
2.将数组nums按照从大到小的顺序排序。
3.创建一个长度为k的数组group,用于存放k个子集的和,初始值都为0。
4.调用partitionK函数,传入group、sum/k、排序后的nums数组和nums数组的长度-1。
5.在partitionK函数中,如果index小于0,表示已经遍历完了数组nums,此时返回true。
6.取出nums[index]作为当前要放入子集的数字。
7.遍历group数组,对于group数组中的每个元素group[i],如果将当前数字nums[index]放入到group[i]中不超过目标和target,则将该数字放入group[i]。
8.递归调用partitionK函数,传入更新过的group、target、nums和index-1。
9.如果递归调用的结果为true,则表示找到了满足条件的分组,返回true。
10.从i+1开始,减少重复计算,跳过和group[i]相等的元素。
11.返回false。
第一种算法的时间复杂度为O(k * 2^n),其中n是数组nums的长度,对于每个状态,需要遍历一次nums数组。
第二种算法的时间复杂度为O(k * n * 2^n),其中n是数组nums的长度,对于每个状态,需要遍历一次group数组和nums数组。
第一种算法的额外空间复杂度为O(2^n),用于存储dp map。
第二种算法的额外空间复杂度为O(k),用于存储group数组。
go完整代码如下:
package main
import (
"fmt"
"sort"
)
func canPartitionKSubsets1(nums []int, k int) bool {
sum := 0
for _, num := range nums {
sum += num
}
if sum%k != 0 {
return false
}
return process1(nums, 0, 0, 0, sum/k, k, make(map[int]int)) == 1
}
func process1(nums []int, status, sum, sets, limit, k int, dp map[int]int) int {
if ans, ok := dp[status]; ok {
return ans
}
ans := -1
if sets == k {
ans = 1
} else {
for i := 0; i < len(nums); i++ {
if (status&(1<<i)) == 0 && sum+nums[i] <= limit {
if sum+nums[i] == limit {
ans = process1(nums, status|(1<<i), 0, sets+1, limit, k, dp)
} else {
ans = process1(nums, status|(1<<i), sum+nums[i], sets, limit, k, dp)
}
if ans == 1 {
break
}
}
}
}
dp[status] = ans
return ans
}
func canPartitionKSubsets2(nums []int, k int) bool {
sum := 0
for _, num := range nums {
sum += num
}
if sum%k != 0 {
return false
}
sort.Ints(nums)
return partitionK(make([]int, k), sum/k, nums, len(nums)-1)
}
func partitionK(group []int, target int, nums []int, index int) bool {
if index < 0 {
return true
}
num := nums[index]
len := len(group)
for i := 0; i < len; i++ {
if group[i]+num <= target {
group[i] += num
if partitionK(group, target, nums, index-1) {
return true
}
group[i] -= num
for i+1 < len && group[i] == group[i+1] {
i++
}
}
}
return false
}
func main() {
nums := []int{4, 3, 2, 3, 5, 2, 1}
k := 4
fmt.Println(canPartitionKSubsets1(nums, k))
fmt.Println(canPartitionKSubsets2(nums, k))
}

rust完整代码如下:
fn can_partition_k_subsets1(nums: Vec<i32>, k: i32) -> bool {
let sum: i32 = nums.iter().sum();
if sum % k != 0 {
return false;
}
let mut dp: Vec<i32> = vec![0; 1 << nums.len()];
process1(nums, 0, 0, 0, sum / k, k, &mut dp) == 1
}
fn process1(
nums: Vec<i32>,
status: usize,
sum: i32,
sets: i32,
limit: i32,
k: i32,
dp: &mut Vec<i32>,
) -> i32 {
if dp[status] != 0 {
return dp[status];
}
let mut ans = -1;
if sets == k {
ans = 1;
} else {
for i in 0..nums.len() {
if (status & (1 << i)) == 0 && sum + nums[i] <= limit {
if sum + nums[i] == limit {
ans = process1(nums.clone(), status | (1 << i), 0, sets + 1, limit, k, dp);
} else {
ans = process1(
nums.clone(),
status | (1 << i),
sum + nums[i],
sets,
limit,
k,
dp,
);
}
if ans == 1 {
break;
}
}
}
}
dp[status] = ans;
return ans;
}
fn can_partition_k_subsets2(nums: Vec<i32>, k: i32) -> bool {
let sum: i32 = nums.iter().sum();
if sum % k != 0 {
return false;
}
let mut sorted_nums = nums.clone();
sorted_nums.sort();
partition_k(
&mut vec![0; k as usize],
sum / k,
&sorted_nums,
(sorted_nums.len() - 1) as i32,
)
}
fn partition_k(group: &mut Vec<i32>, target: i32, nums: &Vec<i32>, index: i32) -> bool {
if index < 0 {
return true;
}
let num = nums[index as usize];
let len = group.len() as i32;
for mut i in 0..len {
if group[i as usize] + num <= target {
group[i as usize] += num;
if partition_k(group, target, nums, index - 1) {
return true;
}
group[i as usize] -= num;
while i + 1 < group.len() as i32 && group[i as usize] == group[(i + 1) as usize] {
i += 1;
}
}
}
false
}
fn main() {
let nums = vec![4, 3, 2, 3, 5, 2, 1];
let k = 4;
let result1 = can_partition_k_subsets1(nums.clone(), k);
let result2 = can_partition_k_subsets2(nums.clone(), k);
println!("Result using can_partition_k_subsets1: {}", result1);
println!("Result using can_partition_k_subsets2: {}", result2);
}

c++完整代码如下:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
bool process1(vector<int>& nums, int status, int sum, int sets, int limit, int k, vector<int>& dp) {
if (dp[status] != 0) {
return dp[status] == 1;
}
bool ans = false;
if (sets == k) {
ans = true;
}
else {
for (int i = 0; i < nums.size(); i++) {
if ((status & (1 << i)) == 0 && sum + nums[i] <= limit) {
if (sum + nums[i] == limit) {
ans = process1(nums, status | (1 << i), 0, sets + 1, limit, k, dp);
}
else {
ans = process1(nums, status | (1 << i), sum + nums[i], sets, limit, k, dp);
}
if (ans) {
break;
}
}
}
}
dp[status] = ans ? 1 : -1;
return ans;
}
bool canPartitionKSubsets1(vector<int>& nums, int k) {
int sum = 0;
for (int num : nums) {
sum += num;
}
if (sum % k != 0) {
return false;
}
vector<int> dp(1 << nums.size(), 0);
return process1(nums, 0, 0, 0, sum / k, k, dp);
}
bool partitionK(vector<int>& group, int target, vector<int>& nums, int index) {
if (index < 0) {
return true;
}
int num = nums[index];
int len = group.size();
for (int i = 0; i < len; i++) {
if (group[i] + num <= target) {
group[i] += num;
if (partitionK(group, target, nums, index - 1)) {
return true;
}
group[i] -= num;
while (i + 1 < group.size() && group[i] == group[i + 1]) {
i++;
}
}
}
return false;
}
bool canPartitionKSubsets2(vector<int>& nums, int k) {
int sum = 0;
for (int num : nums) {
sum += num;
}
if (sum % k != 0) {
return false;
}
sort(nums.begin(), nums.end());
vector<int> t = vector<int>(k, 0);
return partitionK(t, sum / k, nums, nums.size() - 1);
}
int main()
{
vector<int> nums = { 4, 3, 2, 3, 5, 2, 1 };
int k = 4;
bool result1 = canPartitionKSubsets1(nums, k);
cout << "Result using canPartitionKSubsets1: " << (result1 ? "true" : "false") << endl;
bool result2 = canPartitionKSubsets2(nums, k);
cout << "Result using canPartitionKSubsets2: " << (result2 ? "true" : "false") << endl;
return 0;
}

c完整代码如下:
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
int process1(int* nums, int numsSize, int status, int sum, int sets, int limit, int k, int* dp) {
if (dp[status] != 0) {
return dp[status];
}
int ans = -1;
if (sets == k) {
ans = 1;
}
else {
for (int i = 0; i < numsSize; i++) {
if ((status & (1 << i)) == 0 && sum + nums[i] <= limit) {
if (sum + nums[i] == limit) {
ans = process1(nums, numsSize, status | (1 << i), 0, sets + 1, limit, k, dp);
}
else {
ans = process1(nums, numsSize, status | (1 << i), sum + nums[i], sets, limit, k, dp);
}
if (ans == 1) {
break;
}
}
}
}
dp[status] = ans;
return ans;
}
bool canPartitionKSubsets1(int* nums, int numsSize, int k) {
int sum = 0;
for (int i = 0; i < numsSize; i++) {
sum += nums[i];
}
if (sum % k != 0) {
return false;
}
int* dp = (int*)malloc((1 << numsSize) * sizeof(int));
for (int i = 0; i < (1 << numsSize); i++) {
dp[i] = 0;
}
bool result = process1(nums, numsSize, 0, 0, 0, sum / k, k, dp) == 1;
free(dp);
return result;
}
bool partitionK(int* group, int target, int* nums, int index, int len) {
if (index < 0) {
return true;
}
int num = nums[index];
for (int i = 0; i < len; i++) {
if (group[i] + num <= target) {
group[i] += num;
if (partitionK(group, target, nums, index - 1, len)) {
return true;
}
group[i] -= num;
while (i + 1 < len && group[i] == group[i + 1]) {
i++;
}
}
}
return false;
}
bool canPartitionKSubsets2(int* nums, int numsSize, int k) {
int sum = 0;
for (int i = 0; i < numsSize; i++) {
sum += nums[i];
}
if (sum % k != 0) {
return false;
}
for (int i = 0; i < numsSize; i++) {
for (int j = i + 1; j < numsSize; j++) {
if (nums[i] < nums[j]) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
}
int target = sum / k;
int* group = (int*)malloc(k * sizeof(int));
for (int i = 0; i < k; i++) {
group[i] = 0;
}
bool result = partitionK(group, target, nums, numsSize - 1, k);
free(group);
return result;
}
int main() {
int nums[] = { 4, 3, 2, 3, 5, 2, 1 };
int numsSize = sizeof(nums) / sizeof(nums[0]);
int k = 4;
bool result1 = canPartitionKSubsets1(nums, numsSize, k);
bool result2 = canPartitionKSubsets2(nums, numsSize, k);
printf("Result from canPartitionKSubsets1: %s\n", result1 ? "true" : "false");
printf("Result from canPartitionKSubsets2: %s\n", result2 ? "true" : "false");
return 0;
}

2023-09-13:用go语言,给定一个整数数组 nums 和一个正整数 k, 找出是否有可能把这个数组分成 k 个非空子集,其总和都相等。 输入: nums = [4, 3, 2, 3, 5,的更多相关文章
- 【c语言】数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字
题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字. 比如输入一个长度为9的数组{1,2.3.2,2.2.5,4.2}, 因为数组中数字2出现了5次,超过数组的长度的一半,因此输出2 ...
- 给定两个list A ,B,请用找出 A ,B中相同的元素,A ,B中不同的元素 ??
A.B 中相同元素:print(set(A)&set(B)) A.B 中不同元素:print(set(A)^set(B))
- 很火的Java题——判断一个整数是否是奇数
完成以下代码,判断一个整数是否是奇数: public boolean isOdd(int i) 看过<编程珠玑>的人都知道这道题的答案和其中极为简单的道理. 最普遍的风格,如下: 这个函数 ...
- 刷题之给定一个整数数组 nums 和一个目标值 taget,请你在该数组中找出和为目标值的那 两个 整数
今天下午,看了一会github,想刷个题呢,就翻出来了刷点题提高自己的实际中的解决问题的能力,在面试的过程中,我们发现,其实很多时候,面试官 给我们的题,其实也是有一定的随机性的,所以我们要多刷更多的 ...
- 给定一个整数数组 nums 和一个目标值 target,求nums和为target的两个数的下表
这个是来自力扣上的一道c++算法题目: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案 ...
- 给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标。
/** * 给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标. * * 你可以假设每种输入只会对应一个答案.但是,数组中 ...
- 【C语言】输入一个整数N,求N以内的素数之和
[C语言]输入一个整数N,求N以内的素数之和 /* ========================================================================== ...
- 在排序数组中查找元素的第一个和最后一个位置(给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。)
示例 1: 输入: nums = [5,7,7,8,8,10], target = 8 输出: [3,4] 示例 2: 输入: nums = [5,7,7,8,8,10], target = 6 输出 ...
- C语言必会面试题(3、耶稣有13个门徒,当中有一个就是出卖耶稣的叛徒,请用排除法找出这位叛徒:13人围坐一圈,从第一个開始报号:1,2,3,1,2,3...。凡是报到“3”就退出圈子,...)
3.耶稣有13个门徒.当中有一个就是出卖耶稣的叛徒,请用排除法找出这位叛徒:13人围坐一圈,从第一个開始报号:1.2,3.1,2,3.... 凡是报到"3"就退出圈子.最后留在圈子 ...
- C语言:找出一个大于给定整数m且紧随m的素数,-求出能整除x且不是偶数的数的个数,
//函数fun功能:找出一个大于给定整数m且紧随m的素数,并作为函数值返回. #include <stdlib.h> #include <conio.h> #include & ...
随机推荐
- 前端三件套系例之HTML——HTML5基础
1.HTML 1-1 什么是HTML HTML是用来制作网页的标记语言 HTML是Hypertext Markup Language的英文缩写,即超文本标记语言 HTML语言是一种标记语言,不需要编译 ...
- JuiceFS 目录配额功能设计详解
JuiceFS 在最近 v1.1 版本中加入了社区中呼声已久的目录配额功能.已发布的命令支持为目录设置配额.获取目录配额信息.列出所有目录配额等.完整的详细信息,请查阅文档. 在设计此功能时,对于它的 ...
- DP 复习
背包 约定使用 \(v_i\) 表示放入第 \(i\) 件物品的花费,\(w_i\) 表示第 \(i\) 件物品的价值,背包容量 \(M\),物品件数 \(N\). 01 背包 每种物品仅有一件,可以 ...
- P8679 [蓝桥杯 2019 省 B] 填空问题 题解
P8679 [蓝桥杯 2019 省 B] 填空问题 题解 题目传送门 欢迎大家指出错误并联系这个蒟蒻 更新日志 2023-05-25 21:02 文章完成 2023-05-27 11:34 文章通过审 ...
- virsh domxxx命令
1. 摘要信息类 1.1 dominfo 获取配置等摘要信息 [root@hyperhost ~]# virsh dominfo --domain centos7.6 Id: 1 Name: cent ...
- Codeforces Round 905 Div 1 (CF1887)
A1. Dances (Easy version) 把 \(a,b\) 序列都从小到大排序,\(a\) 贪心删大的,\(b\) 贪心删小的,二分答案并 \(O(n)\) \(\text{check}\ ...
- 阿里发布AI编码助手:通义灵码,兼容 VS Code、IDEA等主流编程工具
今天是阿里云栖大会的第一天,相信场外的瓜,大家都吃过了.这里就不说了,有兴趣可以看看这里:云栖大会变成相亲现场,最新招婿鄙视链来了... . 这里主要说说阿里还发布了一款AI编码助手,对于我们开发者来 ...
- java 处理常量字符串过长 & springboot 项目读取 resouces 文件夹下的文件内容
长字符串起因 项目里面有一长串的加密字符串(最长的万多个字符),需要拼接作为参数发送给第三方. 如果我们使用 枚举 定义的话,idea 编译的时候就会出现编译报错 Error: java:常量字符串过 ...
- MySQL锁:InnoDB行锁需要避免的坑
前言 换了工作之后,接近半年没有发博客了(一直加班),emmmm.....今天好不容易有时间,记录下工作中遇到的一些问题,接下来应该重拾知识点了.因为新公司工作中MySQL库经常出现查询慢,锁等待,节 ...
- HelloGitHub 社区动态,开启新的篇章!
今天这篇文章是 HelloGitHub 社区动态的第一篇文章,所以我想多说两句,聊聊为啥开启这个系列. 我是 2016 年创建的 HelloGitHub,它从最初的一份分享开源项目的月刊,现如今已经成 ...