题目:
需要把数组里的数(每个数的取值都是1-9)分成多个小组,分小组的规则是:3个相同的数或者3个连续的数,当所有的数都可以被分组,则为完全分组。
设计一个算法,判断数组是否能完全分组。
例如[1, 1, 2, 2, 2, 3, 3, 3, 4],可分为 123 123 234(完全分组),
注意:若先把222 333分为一组,则会导致出现bug,判断为不可完全分组。
以下提供2个方法,均为c++实现:
方法一: 先查找相同数,并标记出来,再将还没标记的数按连续数方式查找;若得出不可完全分组,再将该数组先按连续数查找,再按相同数查找(原理同上),得出可不可完全分组。
bool CanGroup(vector<int>& nums) {
int n = nums.size(), i = 0, j = 1, k = 2, sign = true;
// 若数组长度不是3的倍数,则无法分组
if (n % 3 != 0) return false;
sort(nums.begin(), nums.end());
vector<int> newNums(nums);
// 查找相同3个数,并标记为已分组(使用-1表示已分组)
while (i < n) {
if (nums[i] == nums[i + 1] && nums[i + 1] == nums[i + 2]) {
newNums[i] = newNums[i + 1] = newNums[i + 2] = -1;
i = i + 3;
} else {
i++;
}
}
i = 0;
// 查找连续3个数,并标记为已分组(使用-1表示已分组)
while (k < n) {
while (newNums[i] == -1 && i < j) {
i++;
}
while (newNums[j] == -1 && j < k) {
j++;
}
while (newNums[k] == -1 && k < n) {
k++;
}
if (nums[i] + 1 == nums[j] && nums[j] + 1 == nums[k]) {
newNums[i] = newNums[j] = newNums[k] = -1;
} else if (nums[i] + 2 != nums[k]) {
k++;
} else if (nums[i] + 1 != nums[j]) {
j++;
}
}
for (int i = 0; i < n; i++) {
if (newNums[i] != -1) sign = false;
}
if (!sign) {
i = 0, j = 1, k = 2;
for (int i = 0; i < newNums.size(); i++) {
newNums[i] = 1;
}
// 查找连续3个数,并标记为已分组(使用-1表示已分组)
while (k < n) {
while (newNums[i] == -1 && i < j) {
i++;
}
while (newNums[j] == -1 && j < k) {
j++;
}
while (newNums[k] == -1 && k < n) {
k++;
}
if (nums[i] + 1 == nums[j] && nums[j] + 1 == nums[k]) {
newNums[i] = newNums[j] = newNums[k] = -1;
} else {
if (nums[i] + 2 != nums[k]) {
k++;
}
if (nums[i] + 1 != nums[j]) {
j++;
}
}
}
i = 0;
// 查找相同3个数,并标记为已分组(使用-1表示已分组)
while (i < n) {
while (newNums[i] == -1 || newNums[i + 1] == -1 || newNums[i + 2] == -1) {
i++;
}
if (nums[i] == nums[i + 1] && nums[i + 1] == nums[i + 2]) {
newNums[i] = newNums[i + 1] = newNums[i + 2] = -1;
i = i + 3;
} else {
i++;
}
}
for (int i = 0; i < n; i++) {
if (newNums[i] != -1) return false;
}
}
return true;
}
方法二(优化算法):
循环查找相同数和连续数,查到一种,最慢指针 i 才可以右移,循环查找结束之后,判断有无完全分组。
bool CanGroupOptimize(vector<int>& nums) {
int n = nums.size(), i = 0, j = 1, k = 2, Stop = false;
// 若数组长度不是3的倍数,则无法分组
if (n % 3 != 0) return false;
sort(nums.begin(), nums.end());//数据排序
vector<int> newNums(nums);//初始化标志数组
while (!Stop) {
Stop = true;
// 循环查找相同3个数,并标记为已分组(使用-1表示已分组)
while (nums[i] == nums[i + 1] && nums[i + 1] == nums[i + 2]) {
newNums[i] = newNums[i + 1] = newNums[i + 2] = -1;
Stop = false;
i = i + 3;
j = i + 1;
k = j + 1;
if (i >= n) {
return true;
}
}
// 循环查找连续3个数,并标记为已分组(使用-1表示已分组)
while (k < n) {
while (newNums[i] == -1 && i < j) {
i++;
}
while (newNums[j] == -1 && j < k) {
j++;
}
while (newNums[k] == -1 && k < n) {
k++;
}
if (nums[i] + 1 == nums[j] && nums[j] + 1 == nums[k]) {
newNums[i] = newNums[j] = newNums[k] = -1;
Stop = false;
} else {
while (nums[i] + 2 != nums[k] && k < n) {
k++;
}
while (nums[i] + 1 != nums[j] && j < k) {
j++;
}
}
}
}
//检索分组标志数组
for (int i = 0; i < n; i++) {
if (newNums[i] != -1) return false;
}
return true;
}
运行结果: