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,的更多相关文章

  1. 【c语言】数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字

    题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字. 比如输入一个长度为9的数组{1,2.3.2,2.2.5,4.2}, 因为数组中数字2出现了5次,超过数组的长度的一半,因此输出2 ...

  2. 给定两个list A ,B,请用找出 A ,B中相同的元素,A ,B中不同的元素 ??

    A.B 中相同元素:print(set(A)&set(B)) A.B 中不同元素:print(set(A)^set(B))

  3. 很火的Java题——判断一个整数是否是奇数

    完成以下代码,判断一个整数是否是奇数: public boolean isOdd(int i) 看过<编程珠玑>的人都知道这道题的答案和其中极为简单的道理. 最普遍的风格,如下: 这个函数 ...

  4. 刷题之给定一个整数数组 nums 和一个目标值 taget,请你在该数组中找出和为目标值的那 两个 整数

    今天下午,看了一会github,想刷个题呢,就翻出来了刷点题提高自己的实际中的解决问题的能力,在面试的过程中,我们发现,其实很多时候,面试官 给我们的题,其实也是有一定的随机性的,所以我们要多刷更多的 ...

  5. 给定一个整数数组 nums 和一个目标值 target,求nums和为target的两个数的下表

    这个是来自力扣上的一道c++算法题目: 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案 ...

  6. 给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标。

    /** * 给定一个整数数组nums和一个整数目标值target,请你在该数组中找出和为目标值target的那两个整数,并返回它们的数组下标. * * 你可以假设每种输入只会对应一个答案.但是,数组中 ...

  7. 【C语言】输入一个整数N,求N以内的素数之和

    [C语言]输入一个整数N,求N以内的素数之和 /* ========================================================================== ...

  8. 在排序数组中查找元素的第一个和最后一个位置(给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。)

    示例 1: 输入: nums = [5,7,7,8,8,10], target = 8 输出: [3,4] 示例 2: 输入: nums = [5,7,7,8,8,10], target = 6 输出 ...

  9. C语言必会面试题(3、耶稣有13个门徒,当中有一个就是出卖耶稣的叛徒,请用排除法找出这位叛徒:13人围坐一圈,从第一个開始报号:1,2,3,1,2,3...。凡是报到“3”就退出圈子,...)

    3.耶稣有13个门徒.当中有一个就是出卖耶稣的叛徒,请用排除法找出这位叛徒:13人围坐一圈,从第一个開始报号:1.2,3.1,2,3.... 凡是报到"3"就退出圈子.最后留在圈子 ...

  10. C语言:找出一个大于给定整数m且紧随m的素数,-求出能整除x且不是偶数的数的个数,

    //函数fun功能:找出一个大于给定整数m且紧随m的素数,并作为函数值返回. #include <stdlib.h> #include <conio.h> #include & ...

随机推荐

  1. EMC ndmp NAS

    NAS 是带存储系统的专用高性能文件服务器.它可提供文件级数据访问和共享. NAS 使用网络和文件共享协议,包括用于数据传输的 TCP/IP 以及用于远程文件服务的 CIFS 和 NFS. 最简单的备 ...

  2. 如何打开关闭Edge鼠标手势

    概述 今天突然发现edge有了一个鼠标手势,用起来不是很适应,所以决定将其关掉. 操作步骤 点击edge右上角的三个点 在下拉菜单中选择设置 点开设置之后出现如图所示的界面,然后选择外观 往下面拉页面 ...

  3. 3.MongoDB-备份恢复

    备份工具 (1)** mongoexport/mongoimport (2)***** mongodump/mongorestore 备份工具区别在那里? 应用场景总结: mongoexport/mo ...

  4. 解密Prompt系列18. LLM Agent之只有智能体的世界

    重新回来聊Agent,前四章的LLM Agent,不论是和数据库和模型还是和搜索引擎交互,更多还是大模型和人之间的交互.这一章我们来唠唠只有大模型智能体的世界!分别介绍斯坦福小镇和Chatdev两篇论 ...

  5. 一篇适合躺收藏夹的 Nexus3 搭建 NuGet&Docker 私有库的安装使用总结

    前言 Nexus 是支持 Nuget.Docker.Npm 等多种包的仓库管理器,可用做私有包的存储分发,缓存官方包.本篇将手把手教学使用 Nexus 搭建自己的 NuGe t& Docker ...

  6. gitlab : You won`t be able to pull or push project code via SSH until you add an SSH key to your profile(导致的问题:合并不了代码)

    gitlab : You won`t be able to pull or push project code via SSH until you add an SSH key to your pro ...

  7. DDD技术方案落地实践

    1. 引言 从接触领域驱动设计的初学阶段,到实现一个旧系统改造到DDD模型,再到按DDD规范落地的3个的项目.对于领域驱动模型设计研发,从开始的各种疑惑到吸收各种先进的理念,目前在技术实施这一块已经基 ...

  8. Spring 缓存注解这样用,太香了!

    作者最近在开发公司项目时使用到 Redis 缓存,并在翻看前人代码时,看到了一种关于 @Cacheable 注解的自定义缓存有效期的解决方案,感觉比较实用,因此作者自己拓展完善了一番后分享给各位. S ...

  9. mysql group by 执行原理及千万级别count 查询优化

    大家好,我是蓝胖子,前段时间mysql经常碰到慢查询报警,我们线上的慢sql阈值是1s,出现报警的表数据有 7000多万,经常出现报警的是一个group by的count查询,于是便开始着手优化这块, ...

  10. Android Sutdio 编入System API 等隐藏API 方法

    1. 将 classes.jar 放入 app/libs 文件夹下 右键点击 jar 包,点击 Add as Library 2. 项目级 Gradle 文件新增以下配置 gradle.project ...