1、题目描述
2、解题思路
题目要求分成一个或者若干个递增子序列,递增子序列有两个特定:从小到大递增、元素不重复。
因此,给定一个数组 nums,假设里面的元素重复次数最多的是数字 x,它重复了 count 次,那么,至少得有 count 个子序列,如果低于 count 个子序列,一定会有子序列有重复的 x 存在。
先把 nums 拆成若干个递增子序列。
1、先从 nums 中找出重复次数最多的数字,假设为 i,重复了 max 次;
2、创建 max 个子序列,然后把这 max 个 i 平均分配给每一个子序列;
3、把 nums 中剩余的元素平均分配给每一个子序列。
以一个例子来说明上面三步,比如:nums = {1,2,2,3,3,4,4,5,6,7}
1、重复次数最多的是 2、3、4,都重复了 2 次;
2、创建 2 个子序列 {} 、{},把 2、3、4 平均分配给每一个子序列,变为{2,3,4} 和 {2,3,4}
3、nums 剩余元素为 {1,5,6},轮流分配给每一个子序列:
{2,3,4} + 1 = {1,2,3,4}
{2,3,4} + 5 = {2,3,4,5}
{1,2,3,4} + 6 = {1,2,3,4,6}
最终的结果就是 {1,2,3,4,6} 和 {2,3,4,5}。
回到题目要求,子序列长度至少为 K,如果 K 为 3,我们上面两个子序列都满足要求,返回 true;如果 K 为 5 ,则{2,3,4,5}不满足要求,返回false。
代码并不用按照上面这样一步步操作,我们只需要使用反证法即可。
找出 nums 中出现次数最大的数字 i 和对应的出现次数 max,创建 max 个子序列。
因为子序列的个数至少是 count 个,最短的子序列长度至少为 K。
如果要满足题目要求,那么所有子序列的元素个数加起来至少为 max × K 个,且子序列的所有元素均来自于 nums。
因此,如果 max × K <= nums.length ,那么一定满足题目要求,反之一定不满足。
这里解释一下为什么:当我们创建了 max 个子序列并把重复了 max 次的数字 i 分配完,这时,nums 剩余元素个数为 residue = nums.length - max,这 residue 个元素是按照从小到大依次分配给每一个子序列,因此子序列不会有重复的数字,并且子序列的元素个数差最多为 1。
当 max × K == nums.length,说明刚好满足题目要求,若 nums 的元素个数不足 max × K 个元素,则一定不满足要求。若 nums 的元素个数大于 max × K,说明不及满足,还绰绰有余。
3、解题代码
class Solution {
public boolean canDivideIntoSubsequences(int[] nums, int K) {
int max = 1; // 最长重复元素个数
int temp = 1; // 当前元素重复个数
for (int i = 1; i < nums.length; i++) {
if (nums[i] == nums[i - 1]) {
temp++;
} else {
max = Math.max(max, temp);
temp = 1;
}
}
max = Math.max(max, temp);
return max * K <= nums.length;
}
}