文章目录
一, O(1) 时间插入、删除和获取随机元素 - 允许重复
设计一个支持在平均 时间复杂度 O(1) 下, 执行以下操作的数据结构。
注意: 允许出现重复元素。
insert(val):向集合中插入元素 val。
remove(val):当 val 存在时,从集合中移除一个 val。
getRandom:从现有集合中随机获取一个元素。每个元素被返回的概率应该与其在集合中的数量呈线性相关。
示例:
// 初始化一个空的集合。
RandomizedCollection collection = new RandomizedCollection();
// 向集合中插入 1 。返回 true 表示集合不包含 1 。
collection.insert(1);
// 向集合中插入另一个 1 。返回 false 表示集合包含 1 。集合现在包含 [1,1] 。
collection.insert(1);
// 向集合中插入 2 ,返回 true 。集合现在包含 [1,1,2] 。
collection.insert(2);
// getRandom 应当有 2/3 的概率返回 1 ,1/3 的概率返回 2 。
collection.getRandom();
// 从集合中删除 1 ,返回 true 。集合现在包含 [1,2] 。
collection.remove(1);
// getRandom 应有相同概率返回 1 和 2 。
collection.getRandom();
通过次数18,251提交次数40,592
二, 解题思路
1 ,插入和删除
①, 插入和删除时间复杂度是 O ( 1 ) O(1) O(1) , 提到时间复杂度为 O ( 1 ) O(1) O(1) 基本就是使用哈希函数解决,然后有可能重复的数据的就要在添加在哈希中添加entry结构中添加计数count的字段 count等于0时就删除这个节点,出现相同就++count就可以的不需要申请内存了
typedef struct entry
{
unsigned long long value;
unsigned long long count;//个数
struct entry * next;
}entry;
② , 哈希碰撞的解决
哈希碰撞使用有序链表把数据给连接起来
/** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */
bool randomizedCollectionInsert(RandomizedCollection* obj, int val)
{
if (!obj)
{
return false;
}
if (obj->used>= obj->size)
{
reset_size(obj);
}
unsigned long long hash = get_hash(obj,val);
obj->arrays[obj->arrays_size++] = val;
++obj->used;
if (obj->table[hash])
{
entry * pre_new_entry_ptr = NULL;
entry * cur_entry_ptr = obj->table[hash];
while (cur_entry_ptr)
{
if (cur_entry_ptr->value >val)
{
break;
}
else if (cur_entry_ptr->value < val)
{
pre_new_entry_ptr = cur_entry_ptr;
cur_entry_ptr = pre_new_entry_ptr->next;
}
else if(cur_entry_ptr->value == val)
{
++cur_entry_ptr->count;
return false;
}
}
//哈希冲突解决
entry * new_entry_ptr = malloc(sizeof(struct entry));
new_entry_ptr->value = val;
new_entry_ptr->next = NULL;
new_entry_ptr->count = 1;
if (pre_new_entry_ptr)
{
pre_new_entry_ptr->next = new_entry_ptr;
new_entry_ptr->next = cur_entry_ptr;
}
else if (!pre_new_entry_ptr && cur_entry_ptr)
{
new_entry_ptr->next = cur_entry_ptr;
obj->table[hash] = new_entry_ptr;
}
return true;
}
else
{
entry * new_entry_ptr = malloc(sizeof(struct entry));
new_entry_ptr->value = val;
new_entry_ptr->next = NULL;
new_entry_ptr->count = 1;
obj->table[hash] = new_entry_ptr;
}
return true;
}
2, 随机数 时间复杂度 O ( 1 ) O(1) O(1)
所有的数都参与 要求时间复杂度在 O ( 1 ) O(1) O(1), 这个基本是数组访问就是 O ( 1 ) O(1) O(1)
①, 插入
插入时间复杂度是O(1)
插入末尾不需要移动数组
obj->arrays[obj->arrays_size++] = val;
②, 删除
删除的时间复杂度最好是 O ( 1 ) O(1) O(1) 在第一个位置, 最差就是 O ( N ) O(N) O(N) ,在数组的最后一个
for(int i = 0; i < obj->arrays_size; ++i)
{
if (obj->arrays[i] == val)
{
obj->arrays[i] = obj->arrays[--obj->arrays_size];
break;
}
}
三, 解题程序
typedef struct entry
{
unsigned long long value;
struct entry * next;
unsigned long long count;//个数
}entry;
typedef struct {
entry** table;// 数组指针
unsigned long long size; //hash大小
unsigned long long mask; //哈希因子
unsigned long long used;
int * arrays ; // 动态数组 查询时的时间复杂度O(N)
unsigned long long arrays_size; //动态数组总有数据的个数
} RandomizedCollection;
#define hash_init_size 5
unsigned long long get_hash(RandomizedCollection * random_ptr, int value)
{
return value %random_ptr->mask;
}
//动态扩容
void reset_size(RandomizedCollection * random_ptr)
{
random_ptr->size = random_ptr->size *2;
random_ptr->mask = random_ptr->size - 1;
//alloc 空间
entry ** new_table_ptr = malloc(sizeof(struct entry *)*random_ptr->size);
for (unsigned long long i = 0; i < random_ptr->size; ++i)
{
new_table_ptr[i] = NULL;
}
random_ptr->arrays = realloc(random_ptr->arrays, sizeof(int) * random_ptr->size);
for (unsigned long long i = 0; i < random_ptr->size/2; ++i)
{
if (random_ptr->table[i])
{
entry * cur_entry_ptr = random_ptr->table[i];
while(cur_entry_ptr)
{
entry * next_entry_ptr = cur_entry_ptr->next;
unsigned long long hash = get_hash(random_ptr, cur_entry_ptr->value);
entry * pre_new_entry_ptr = NULL;
entry * new_entry_ptr = new_table_ptr[hash];
while (new_entry_ptr)
{
if (new_entry_ptr->value > cur_entry_ptr->value)
{
break;
}
else if (new_entry_ptr->value < cur_entry_ptr->value)
{
pre_new_entry_ptr = new_entry_ptr;
new_entry_ptr = new_entry_ptr->next;
}
else
{
// printf("error reset size hash table \n");
}
}
if (pre_new_entry_ptr &&new_entry_ptr)
{
pre_new_entry_ptr->next = cur_entry_ptr;
cur_entry_ptr->next = new_entry_ptr;
}
else if (pre_new_entry_ptr && !new_entry_ptr)//插入末尾
{
pre_new_entry_ptr->next = cur_entry_ptr;
cur_entry_ptr->next = new_entry_ptr;
}
else if (!pre_new_entry_ptr && new_entry_ptr)//插入头部
{
cur_entry_ptr->next = new_entry_ptr;
new_table_ptr[hash] = cur_entry_ptr;
}
else if (!pre_new_entry_ptr && !new_entry_ptr) //该表格没有数据
{
new_table_ptr[hash] = cur_entry_ptr;
cur_entry_ptr->next = NULL;
}
cur_entry_ptr = next_entry_ptr;
}
}
}
if (random_ptr->table)
{
free(random_ptr->table);
random_ptr->table = NULL;
}
random_ptr->table = new_table_ptr;
}
/** Initialize your data structure here. */
RandomizedCollection* randomizedCollectionCreate()
{
RandomizedCollection * random_ptr = malloc(sizeof(*random_ptr));
random_ptr->size = hash_init_size;
random_ptr->mask = hash_init_size -1;
random_ptr->used = 0;
random_ptr->arrays_size = 0;
random_ptr->table = malloc(sizeof(struct entry*)*hash_init_size);
for (unsigned long long i = 0; i < hash_init_size; ++i)
{
random_ptr->table[i] = NULL;
}
random_ptr->arrays = malloc(sizeof(int) * hash_init_size);
memset(random_ptr->arrays, 0, sizeof(int) * hash_init_size);
return random_ptr;
}
/** Inserts a value to the collection. Returns true if the collection did not already contain the specified element. */
bool randomizedCollectionInsert(RandomizedCollection* obj, int val)
{
if (!obj)
{
return false;
}
if (obj->used>= obj->size)
{
reset_size(obj);
}
unsigned long long hash = get_hash(obj,val);
obj->arrays[obj->arrays_size++] = val;
++obj->used;
if (obj->table[hash])
{
entry * pre_new_entry_ptr = NULL;
entry * cur_entry_ptr = obj->table[hash];
while (cur_entry_ptr)
{
if (cur_entry_ptr->value >val)
{
break;
}
else if (cur_entry_ptr->value < val)
{
pre_new_entry_ptr = cur_entry_ptr;
cur_entry_ptr = pre_new_entry_ptr->next;
}
else if(cur_entry_ptr->value == val)
{
++cur_entry_ptr->count;
return false;
}
}
//哈希冲突解决
entry * new_entry_ptr = malloc(sizeof(struct entry));
new_entry_ptr->value = val;
new_entry_ptr->next = NULL;
new_entry_ptr->count = 1;
if (pre_new_entry_ptr)
{
pre_new_entry_ptr->next = new_entry_ptr;
new_entry_ptr->next = cur_entry_ptr;
}
else if (!pre_new_entry_ptr && cur_entry_ptr)
{
new_entry_ptr->next = cur_entry_ptr;
obj->table[hash] = new_entry_ptr;
}
return true;
}
else
{
entry * new_entry_ptr = malloc(sizeof(struct entry));
new_entry_ptr->value = val;
new_entry_ptr->next = NULL;
new_entry_ptr->count = 1;
obj->table[hash] = new_entry_ptr;
}
return true;
}
/** Removes a value from the collection. Returns true if the collection contained the specified element. */
bool randomizedCollectionRemove(RandomizedCollection* obj, int val)
{
if (!obj)
{
return false;
}
unsigned long long hash = get_hash(obj, val);
// printf("val = %d, hash = %lu, obj->size = %lu\n", val, hash, obj->size);
if (obj->table[hash])
{
entry * cur_entry_ptr = obj->table[hash];
entry * pre_entry_ptr = NULL;
while (cur_entry_ptr)
{
entry * next_entry_ptr = cur_entry_ptr->next;
if (cur_entry_ptr->value == val)
{
--obj->used;
if (cur_entry_ptr->count < 2)
{
if (!pre_entry_ptr)
{
obj->table[hash] = next_entry_ptr;
}
else
{
pre_entry_ptr->next = next_entry_ptr;
}
// printf("value = %d, count = %d\n", cur_entry_ptr->value, cur_entry_ptr->count);
free(cur_entry_ptr);
cur_entry_ptr = NULL;
}
else
{
// printf("--value = %d, count = %d\n", cur_entry_ptr->value, cur_entry_ptr->count);
--cur_entry_ptr->count;
}
for(int i = 0; i < obj->arrays_size; ++i)
{
if (obj->arrays[i] == val)
{
obj->arrays[i] = obj->arrays[--obj->arrays_size];
break;
}
}
return true;
}
else if(cur_entry_ptr->value < val)
{
// printf("cur value = %d, value = %d\n", cur_entry_ptr->value, val);
}
else if (cur_entry_ptr->value > val)
{
// printf("remove value = %d\n", val);
return false;
}
// else
{
// printf("remove value = %d\n", val);
}
pre_entry_ptr = cur_entry_ptr;
cur_entry_ptr = next_entry_ptr;
}
}
return false;
}
/** Get a random element from the collection. */
int randomizedCollectionGetRandom(RandomizedCollection* obj)
{
if (!obj||obj->used <1)
{
return 0;
}
if (obj->arrays_size<1)
{
return -1;
}
return obj->arrays[rand() % obj->arrays_size];
}
void randomizedCollectionFree(RandomizedCollection* obj)
{
if (!obj)
{
return;
}
if(obj->arrays)
{
free(obj->arrays);
}
for (int i = 0; i< obj->size; ++i)
{
if (obj->table[i])
{
entry * cur_entry_ptr = obj->table[i];
while (cur_entry_ptr)
{
entry * next_entry_ptr = cur_entry_ptr->next;
free(cur_entry_ptr);
cur_entry_ptr = NULL;
cur_entry_ptr = next_entry_ptr;
}
}
}
free(obj->table);
obj->table = NULL;
free(obj);
obj = NULL;
}
/**
* Your RandomizedCollection struct will be instantiated and called as such:
* RandomizedCollection* obj = randomizedCollectionCreate();
* bool param_1 = randomizedCollectionInsert(obj, val);
* bool param_2 = randomizedCollectionRemove(obj, val);
* int param_3 = randomizedCollectionGetRandom(obj);
* randomizedCollectionFree(obj);
*/
四, 总结
时间复杂度是 O ( 1 ) O(1) O(1),基本就是数组问题解决