381. O(1) 时间插入、删除和获取随机元素 - 允许重复之哈希函数和随机数的动态数组

一, 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),基本就是数组问题解决

源码地址:https://github.com/chensongpoixs/cleet_code

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值