文章目录

  • 1 理解题目
  • 2 分析
  • 2.1进一步优化
  • 2.2 根据花花酱解答

1 理解题目

Given an array of integers nums and a positive integer k, find whether it’s possible to divide this array into k non-empty subsets whose sums are all equal.
输入:一个int数组nums,一个int k
规则:将nums分成k个子数组,每个子数组的和相等
输出:true:如果可以将nums分成k个和相等的子数组。否则false。

Example 1:

Input: nums = [4, 3, 2, 3, 5, 2, 1], k = 4
Output: True
Explanation: It’s possible to divide it into 4 subsets (5), (1, 4), (2,3), (2,3) with equal sums.

2 分析

nums能分成k份,每一份的和应该是总和/k。那就首先确认:总和%k=0。
每一个子数组的和应该是:target=总和/k。如果某个元素的值>target,那也是不可分的。每个元素至少有一个元素,比target大的元素单独成一个子数组,不符合和为target的要求。

现在就该想怎么把这些元素分到k个子数组中。
最开始映入我脑中的是双指针。将nums排序,一个指针从左开始,一个指针从右开始。后来一想,子数组中的元素不一定是2个,被例题束缚了思维。那就不能这样做。但数组排序应该对。至于为什么,还不清楚。

那就尝试用枚举的方法。参考力扣官网。
将第0个元素1,可以放在第0个子数组中、第1个子数组、第2个子数组、第3个子数组。
将第1个元素2,尝试放入第0,1,2,3个子数组,只要放入之后的和不超过target即可。

一直放到最后一个元素,将所有数字都放入了子数组中。

这里放入的过程不是直接将元素放进去,而是放入的是元素的和。

一个重要的细节是,通过判断 if (groups[i] == 0) break;这是因为在尝试了各种可能之后,groups[i]没有合适的选项,所以直接返回false;

class Solution {private int[] nums;public boolean canPartitionKSubsets(int[] nums, int k) {int sum = Arrays.stream(nums).sum();if(sum % k >0) return false;int target = sum/k;       Arrays.sort(nums);if(nums[nums.length-1]>target) return false;this.nums  = nums;int[] groups = new int[k];return dfs(groups,0,target);}private boolean dfs(int[] group, int index, int target){if(index>=nums.length) return true;int  v = nums[index++];for(int i=0;i<group.length;i++){if(group[i] + v<=target){group[i] += v;if(dfs(group,index,target)) return true;group[i] -= v;}if(group[i] == 0) break;}return false;}
}

2.1进一步优化

优化的第一个地方是将数组末尾直接等于target的删除。这个步骤优化效果不明显。
优化的第二个地方是遍历nums从最大值开始遍历。自己可以手写一下[1,2,2,3,3,4,5]这个例子,从大到小,与从小到大的枚举情况,可以发现从大到小,可以很快找到答案。

class Solution {private int[] nums;public boolean canPartitionKSubsets(int[] nums, int k) {int sum = Arrays.stream(nums).sum();if(sum % k >0) return false;int target = sum/k;       Arrays.sort(nums);if(nums[nums.length-1]>target) return false;this.nums  = nums;int index = nums.length-1;while(index>=0 && nums[index]==target){index--;k--;}int[] groups = new int[k];return dfs(groups,index,target);}private boolean dfs(int[] group, int index, int target){if(index<0) return true;int  v = nums[index--];for(int i=0;i<group.length;i++){if(group[i] + v<=target){group[i] += v;if(dfs(group,index,target)) return true;group[i] -= v;}if(group[i] == 0) break;}return false;}
}

时间复杂度O(kN−kk!)O(k^{N-k}k!)O(kN−kk!),N是nums的长度。

2.2 根据花花酱解答

c++代码可以过,java代码超时。来源地址。

class Solution {private int[] nums;public boolean canPartitionKSubsets(int[] nums, int k) {int sum = Arrays.stream(nums).sum();if(sum%k!=0) return false;int target = sum/k;if(nums[nums.length-1]>target) return false;Arrays.sort(nums);this.nums = nums;return dfs(0,0,k,target);}private boolean dfs(int current,int used,int k,int target){if(k==0) return (used == (1<<nums.length)-1);for(int i=0;i<nums.length;i++){if((used & (1<<i))>0) continue;int t = current + nums[i];if(t>target) break;int newUsed = (used | (1<<i));if(t==target){if(dfs(0,newUsed,k-1,target)) return true;}else{if(dfs(t,newUsed,k,target)) return true;}}return false;}}

698. Partition to K Equal Sum Subsets相关推荐

  1. leetcode 698. Partition to K Equal Sum Subsets | 698. 划分为k个相等的子集(回溯法)

    题目 https://leetcode.com/problems/partition-to-k-equal-sum-subsets/ 题解 一上来以为是 dp(想到了左神讲的,将一个数组分成两个尽可能 ...

  2. HDU-3280 Equal Sum Partitions

    http://acm.hdu.edu.cn/showproblem.php?pid=3280 用了简单的枚举. Equal Sum Partitions Time Limit: 2000/1000 M ...

  3. Leetcode 698. 划分为k个相等的子集 解题思路及C++实现

    解题思路: 这是一个典型的深度优先搜索问题.使用一个相同大小的数组visited来记录元素是否被访问过(即是被已被划分到相应的子集中). 每找到一个划分子集,相应对k减一,再继续执行深度优先搜索程序. ...

  4. LeetCode 698. 划分为k个相等的子集(回溯)

    文章目录 1. 题目 2. 解题 1. 题目 给定一个整数数组 nums 和一个正整数 k,找出是否有可能把这个数组分成 k 个非空子集,其总和都相等. 示例 1: 输入: nums = [4, 3, ...

  5. 698. 划分为k个相等的子集:给定一个整数数组 nums 和一个正整数 k,找出是否有可能把这个数组分成 k 个非空子集,其总和都相等。

    题目描述 给定一个整数数组 nums 和一个正整数 k,找出是否有可能把这个数组分成 k 个非空子集,其总和都相等. 示例 1: 输入: nums = [4, 3, 2, 3, 5, 2, 1], k ...

  6. 力扣 698. 划分为k个相等的子集

    题目 给定一个整数数组 nums 和一个正整数 k,找出是否有可能把这个数组分成 k 个非空子集,其总和都相等. 示例 输入: nums = [4, 3, 2, 3, 5, 2, 1], k = 4 ...

  7. [Swift]LeetCode1013. 将数组分成和相等的三个部分 | Partition Array Into Three Parts With Equal Sum...

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ➤微信公众号:山青咏芝(shanqingyongzhi) ➤博客园地址:山青咏芝(https://www.cnblog ...

  8. [Swift]LeetCode1043. 分隔数组以得到最大和 | Partition Array for Maximum Sum

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ➤微信公众号:山青咏芝(shanqingyongzhi) ➤博客园地址:山青咏芝(https://www.cnblog ...

  9. CodeForces - 1328F Make k Equal(模拟)

    题目链接:点击查看 题目大意:给出一个数列 a ,现在有两种操作: 找到一个最小值,使其值加一 找到一个最大值,使其值减一 注意这里找到一个最值进行的操作,是针对最值不唯一的情况,题目问至少需要进行多 ...

最新文章

  1. 三阶魔方还原步骤图_(六)最简单的三阶魔方入门教程——顶面还原
  2. 完美解决 keil5.25 某宝Jlink无法使用问题
  3. Python 学习笔记(3)对txt文件的读与写操作(上)
  4. grub2从usb启动
  5. FFMPEG音视频解码
  6. 使用Azure Pipelines从GitHub发布NuGet包
  7. 公众号出现该公众号提供的服务出现故障分析
  8. topcoder srm 625 div1
  9. python关键字的意思_python 关键字(Keywords)
  10. python 反爬策略_如何应对网站反爬虫策略?如何高效地爬大量数据?
  11. 基于springboot的失物招领系统
  12. jvm虚拟机_JVM虚拟机JVM简介
  13. HiJson——Json解析工具
  14. Flutter - 微信朋友圈效果实现
  15. Pandas 多个工作表、工作簿
  16. logstash过滤器--mutate
  17. 扫码支付java,详解JAVA后端实现统一扫码支付:微信篇
  18. 10GBASE-T SFP+电口模块知识百科
  19. 笔记本nc10装linux,三星nc10笔记本如何设置U盘启动
  20. VIVADO软件学习

热门文章

  1. 【iCore3应用开发平台】发布 iCore3 应用开发平台出厂代码rev0.0.2
  2. 关于webservice(CXF)的一些理解
  3. 每次新建Android项目都报样式找不到的错误?
  4. 为什么到今天还要坚持写博客(转)
  5. spring拦截器-过滤器的区别
  6. Java 计算两个日期时间差,天数、时、分、秒
  7. 跳出内层循环 使用 for of 代替 map
  8. mongo php update 写法,mongodb update 字符 操作
  9. mysql5.7.11 创建用户_修改更新查找MySQL5.7.x的root用户的默认密码
  10. flask 接口 让别人能访问_flask搭建一个前后端分离的系统