分割数组为连续子序列
题目
给你一个按升序排序的整数数组 num(可能包含重复数字),请你将它们分割成一个或多个子序>列,其中每个子序列都由连续整数组成且长度至少为 3 。
如果可以完成上述分割,则返回 true ;否则,返回 false 。
示例 1:
输入: [1,2,3,3,4,5]
输出: True
解释:
你可以分割出这样两个连续子序列 :
1, 2, 3
3, 4, 5示例 2:
输入: [1,2,3,3,4,4,5,5]
输出: True
解释:
你可以分割出这样两个连续子序列 :
1, 2, 3, 4, 5
3, 4, 5示例 3:
输入: [1,2,3,4,4,5]
输出: False提示:
输入的数组长度范围为 [1, 10000]
解题思路
第一遍自己没有做出来,看了题解后选择了使用双哈希表,加贪心算法。具体思路如下:
- 使用两个哈希表,第一个用来统计每个数字出现的次数。第二个用来统计以每个数字结尾的子串的数量,
- 在第一次循环,初始化第一个哈希表。
- 第二次循环开始判断,首先取出第i个数字,判断该数字剩余未使用的次数,如果已经为0,则跳过到下一个数字继续判断。
- 如果第i个的未使用次数不为0,此时要分为两种情况。
- 判断是否有以第i - 1结尾符合要求的子串,如果有将第二个哈希表中以i - 1结尾的子串数量减1,以i结尾的子串数量加1。
- 如果此时没有以i - 1结尾的子串,则需要用该数字做为头,i + 1,i + 2组成新的子串,如果i + 1,i + 2的未使用次数小于0,则返回false。否则将第二个哈希表中以i + 2结尾的子串数量加1。
具体代码如下
struct hashTable{
int val;
int key;
UT_hash_handle hh;
/* data */
};
struct hashTable* find(struct hashTable** hashtable, int key){
struct hashTable* tmp = malloc(sizeof(struct hashTable));
HASH_FIND_INT(*hashtable, &key, tmp);
return tmp;
}
void insert(struct hashTable** hashtable, int key, int val){
struct hashTable* tmp = malloc(sizeof(struct hashTable));
tmp->key = key;
tmp->val = val;
HASH_ADD_INT(*hashtable, key, tmp);
}
/*初始化第一个计数哈希表*/
void initial(struct hashTable** hashtable, int key){
struct hashTable* tmp = find(hashtable, key);
if (tmp == NULL){
insert(hashtable, key, 1);
}else{
tmp->val++;
}
}
int sum_count(struct hashTable** hashtable, int key){
struct hashTable* tmp = find(hashtable, key);
if (tmp == NULL){
return 0;
}else{
return tmp->val;
}
}
void lin(struct hashTable** hashtable, int key, int val){
struct hashTable* tmp = find(hashtable, key);
if (tmp == NULL){
insert(hashtable, key, val);
}else{
tmp->val = val;
}
}
void ins(struct hashTable** hashtable, int key){
struct hashTable* tmp = find(hashtable, key);
if (tmp == NULL){
insert(hashtable, key, 1);
}else{
tmp->val++;
}
}
bool isPossible(int* nums, int numsSize){
struct hashTable* countHash = NULL;
struct hashTable* endHash = NULL;
//初始化第一个哈希
for(int i = 0; i < numsSize; i++){
initial(&countHash, nums[i]);
}
//开始判断,并初始化第二个哈希
for (int i = 0; i < numsSize; i++){
//判断当前数字未使用次数
int count = sum_count(&countHash, nums[i]);
if (count > 0){
//判断是否有以前一个数结尾的子串
int precount = sum_count(&endHash,nums[i]- 1);//如果用num[i - 1]可能会越界
if(precount > 0){
lin(&countHash, nums[i], count - 1);//次数减一
lin(&endHash, nums[i] - 1, precount - 1);
ins(&endHash, nums[i]);
}else{
int count_1 = sum_count(&countHash, nums[i] + 1);
int count_2 = sum_count(&countHash, nums[i] + 2);
if(count_1 > 0 && count_2 > 0){
lin(&countHash, nums[i], count - 1);
lin(&countHash, nums[i] + 1, count_1 - 1);
lin(&countHash, nums[i] + 2, count_2 - 1);
ins(&endHash, nums[i] + 2);
}else{
return false;
}
}
}
}
return true;
}

浙公网安备 33010602011771号