饭不食,水不饮,题必须刷
C语言免费动漫教程,和我一起打卡! 《光天化日学C语言》
LeetCode 太难?先看简单题! 《C语言入门100例》
数据结构难?不存在的! 《画解数据结构》
LeetCode 太简单?算法学起来! 《夜深人静写算法》
设计一个支持在平均 时间复杂度 O ( 1 ) O(1) O(1) 下,执行以下操作的数据结构。
insert(val)
:当元素 v a l val val 不存在时,向集合中插入该项。
remove(val)
:元素 v a l val val 存在时,从集合中移除该项。
getRandom
:随机返回现有集合中的一项。每个元素应该有相同的概率被返回。
样例输入:["RandomizedSet","insert","remove","insert","getRandom","remove","insert","getRandom"] [[],[1],[2],[2],[],[1],[2],[]]
样例输出:[null,true,false,true,2,true,false,2]
typedef struct {
} RandomizedSet;
/** Initialize your data structure here. */
RandomizedSet* randomizedSetCreate() {
}
/** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
bool randomizedSetInsert(RandomizedSet* obj, int val) {
}
/** Removes a value from the set. Returns true if the set contained the specified element. */
bool randomizedSetRemove(RandomizedSet* obj, int val) {
}
/** Get a random element from the set. */
int randomizedSetGetRandom(RandomizedSet* obj) {
}
void randomizedSetFree(RandomizedSet* obj) {
}
/**
* Your RandomizedSet struct will be instantiated and called as such:
* RandomizedSet* obj = randomizedSetCreate();
* bool param_1 = randomizedSetInsert(obj, val);
* bool param_2 = randomizedSetRemove(obj, val);
* int param_3 = randomizedSetGetRandom(obj);
* randomizedSetFree(obj);
*/
( 1 ) (1) (1) 380. O(1) 时间插入、删除和获取随机元素
( 2 ) (2) (2) 剑指 Offer II 030. 插入、删除和随机访问都是 O(1) 的容器
1)维护一个哈希表和两个映射数组,这两个数组分别是 哈希地址到数组下标 的映射,和 数组下标到哈希地址 的映射;
2)插入操作:对哈希表执行查找,如果没有找到,则执行插入,插入过程中更新两个映射数组;
3)删除操作:对哈希表执行查找,如果找到,则执行删除,删除过程中对映射数组执行和最后一个元素进行交换,保证删除是 O ( 1 ) O(1) O(1) 的;
4)随机获取:对 数组下标到哈希地址 这个映射数组进行随机,得到一个哈希地址,再去哈希表中直接通过下标索引找到关键字后返回即可;
/******************** 哈希表 开放定址法 ********************/
#define maxn (1<<17)
#define mask (maxn-1)
#define DataType int
#define Boolean int
#define NULLKEY (1<<30) /* 空槽标记不能用-1,会导致正常值也为-1的情况*/
typedef struct {
DataType data[maxn];
}HashTable;
void HashInit(HashTable *ht) {
int i;
for(i = 0; i < maxn; ++i) {
ht->data[i] = NULLKEY;
}
}
int HashGetAddr(DataType key) {
return key & mask; // 除留余数法
}
Boolean HashSearchKey(HashTable *ht, DataType key, int *addr) {
int startaddr = HashGetAddr(key);
*addr = startaddr;
while(ht->data[*addr] != key) {
*addr = HashGetAddr(*addr + 1);
if(ht->data[*addr] == NULLKEY) {
return 0; // 遇到了空槽,说明没找到,返回 0
}
if(*addr == startaddr) {
return 0; // 找了一圈都没找到,循环了
}
}
return 1;
}
int HashInsert(HashTable *ht, DataType key) {
int addr = HashGetAddr(key);
int retaddr;
if ( HashSearchKey(ht, key, &retaddr ) ) {
return retaddr;
}
while(ht->data[addr] != NULLKEY)
addr = HashGetAddr(addr + 1);
ht->data[addr] = key;
return addr;
}
int HashRemove(HashTable *ht, DataType key) {
int addr;
if ( !HashSearchKey(ht, key, &addr ) ) {
return NULLKEY;
}
ht->data[addr] = NULLKEY;
return addr;
}
/******************** 哈希表 开放定址法 ********************/
typedef struct {
HashTable ht;
int addr2pos[maxn]; // (1)
int pos2addr[maxn]; // (2)
int pos;
} RandomizedSet;
/** Initialize your data structure here. */
RandomizedSet* randomizedSetCreate() {
RandomizedSet *rs = (RandomizedSet *)malloc( sizeof(RandomizedSet) );
HashInit( &rs->ht );
rs->pos = 0; // (3)
return rs;
}
/** Inserts a value to the set. Returns true if the set did not already contain the specified element. */
bool randomizedSetInsert(RandomizedSet* obj, int val) {
int addr;
if (!HashSearchKey(&obj->ht, val, &addr)) {
addr = HashInsert(&obj->ht, val);
obj->addr2pos[ addr ] = obj->pos; // (4)
obj->pos2addr[ obj->pos++ ] = addr; // (5)
return true;
}
return false;
}
void swap(int *a, int *b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
/** Removes a value from the set. Returns true if the set contained the specified element. */
bool randomizedSetRemove(RandomizedSet* obj, int val) {
int addr, pre;
if (HashSearchKey(&obj->ht, val, &addr)) {
addr = HashRemove( &obj->ht, val );
pre = obj->addr2pos[ addr ]; // (6)
obj->addr2pos[ obj->pos2addr[obj->pos-1] ] = pre; // (7)
swap( &obj->pos2addr[pre], &obj->pos2addr[obj->pos-1] ); // (8)
-- obj->pos;
return true;
}
return false;
}
/** Get a random element from the set. */
int randomizedSetGetRandom(RandomizedSet* obj) {
return obj->ht.data[ obj->pos2addr[ rand() % obj->pos ] ];
}
void randomizedSetFree(RandomizedSet* obj) {
free(obj);
}
/**
* Your RandomizedSet struct will be instantiated and called as such:
* RandomizedSet* obj = randomizedSetCreate();
* bool param_1 = randomizedSetInsert(obj, val);
* bool param_2 = randomizedSetRemove(obj, val);
* int param_3 = randomizedSetGetRandom(obj);
* randomizedSetFree(obj);
*/
在一个数组中删除数据,可以将它和最后一个数组元素进行交换,然后再将数组的size减一,这样可以做到 O ( 1 ) O(1) O(1),只不过这样做会改变原有数组顺序,如果对顺序要求不大就可以这么做。