HashMap の簡単な設計
組み込みのハッシュ テーブル ライブラリを使用せずに HashMap を設計します。
MyHashMap クラスを実装します。
MyHashMap() は、空のマップを使用してオブジェクトを初期化します。
void put(int key, int value) は、(key, value) ペアを HashMap に挿入します。キーがマップにすでに存在する場合は、対応する値を更新します。
int get(int key) は、指定されたキーがマップされている値を返します。このマップにキーのマッピングが含まれていない場合は -1 を返します。
void Remove(key) は、マップにキーのマッピングが含まれている場合、キーとその対応する値を削除します。
例 1:
入力
["MyHashMap", "put", "put", "get", "get", "put", "get", "remove", "get"] [[], [1, 1], [
2 、2]、[1]、[3]、[2、1]、[2]、[2]、[2]] 出力 [null、null、null、1、-1、null、1、null
、
- 1]
説明
MyHashMap myHashMap = new MyHashMap();
myHashMap.put(1, 1); // マップは現在 [[1,1]]
myHashMap.put(2, 2); // マップは現在 [[1,1], [2,2]]
myHashMap.get(1); // 1 を返します。マップは現在 [[1,1], [2,2]]
myHashMap.get(3); // return -1 (つまり、見つからない)、マップは現在 [[1,1], [2,2]]
myHashMap.put(2, 1); // マップは [[1,1], [2,1]] になりました (つまり、既存の値を更新します)
myHashMap.get(2); // 1 を返します。マップは現在 [[1,1], [2,1]]
myHashMap.remove(2); // 2 のマッピングを削除します。マップは [[1,1]]
myHashMap.get(2);になります。// return -1 (つまり、見つからない)、マップは現在 [[1,1]] です
制約:
0 <= キー、値 <= 106
put、get、remove の呼び出しは最大 104 回行われます。
解決策 1: 二重ベクトルを使用します。
#define HASHTABLE_SIZE 1001
class MyHashMap {
public:
MyHashMap() {
data.resize(HASHTABLE_SIZE, vector<int>());
}
void put(int key, int value) {
int newKey = key % HASHTABLE_SIZE;
if (data[newKey].empty()) data[newKey].resize(HASHTABLE_SIZE, -1);
data[newKey][key / HASHTABLE_SIZE] = value;
}
int get(int key) {
int newKey = key % HASHTABLE_SIZE;
if (data[newKey].empty()) return -1;
return data[newKey][key / HASHTABLE_SIZE];
}
void remove(int key) {
int newKey = key % HASHTABLE_SIZE;
if (data[newKey].empty()) return;
data[newKey][key / HASHTABLE_SIZE] = -1;
}
private:
vector<vector<int>> data;
};
/**
* Your MyHashMap object will be instantiated and called as such:
* MyHashMap* obj = new MyHashMap();
* obj->put(key,value);
* int param_2 = obj->get(key);
* obj->remove(key);
*/
解決策 2: 上記と似ていますが、ポインターの配列を使用して実装されます。
#define HASHTABLE_SIZE 1001
class MyHashMap {
public:
MyHashMap() {
}
void put(int key, int value) {
int newKey = key % HASHTABLE_SIZE;
if (data[newKey] == NULL) {
data[newKey] = (int *)malloc(HASHTABLE_SIZE * sizeof(int));
for (int i = 0; i < HASHTABLE_SIZE; i++) data[newKey][i] = -1;
}
data[newKey][key / HASHTABLE_SIZE] = value;
}
int get(int key) {
int newKey = key % HASHTABLE_SIZE;
if (data[newKey] == NULL) return -1;
return data[newKey][key / HASHTABLE_SIZE];
}
void remove(int key) {
int newKey = key % HASHTABLE_SIZE;
if (data[newKey] == NULL) return;
data[newKey][key / HASHTABLE_SIZE] = -1;
}
private:
int *data[HASHTABLE_SIZE] = {
0};
};
/**
* Your MyHashMap object will be instantiated and called as such:
* MyHashMap* obj = new MyHashMap();
* obj->put(key,value);
* int param_2 = obj->get(key);
* obj->remove(key);
*/
解決策 3: 上記の方法はどれも多くのスペースを必要とするため、実際には不要です。新しいノードでは、追加されるノードの数。追加する際はリンク先リストの先頭に追加するように注意してください。次回訪問時にキャッチヒットにより早期に遭遇しやすくなります。
#define HASHTABLE_SIZE 1001
struct Node {
int key;
int value;
Node *next;
Node(int k, int v) : key(k), value(v), next(NULL) {
}
};
class MyHashMap {
public:
MyHashMap() {
}
void put(int key, int value) {
int newKey = key % HASHTABLE_SIZE;
if (data[newKey] == nullptr) {
data[newKey] = new Node(key, value);
} else {
Node *head = data[newKey], *p = head;
while (p) {
if (p->key == key) {
p->value = value;
return;
}
p = p->next;
}
Node *newNode = new Node(key, value);
newNode->next = data[newKey];
data[newKey] = newNode;
}
}
int get(int key) {
int newKey = key % HASHTABLE_SIZE;
if (data[newKey] == nullptr) return -1;
Node *head = data[newKey], *p = head;
while (p) {
if (p->key == key) {
return p->value;
}
p = p->next;
}
return -1;
}
void remove(int key) {
int newKey = key % HASHTABLE_SIZE;
if (data[newKey] == nullptr) return;
Node *head = data[newKey];
Node *dummy = new Node(0, 0);
dummy->next = head;
Node *prev = dummy, *p = head;
while (p) {
if (p->key == key) {
prev->next = p->next;
p->value = -1; //It is not necessary here. For remove, the node is actually deleted; set it as -1 to pass the test
//delete(p);
//p = nullptr;
return;
}
p = p->next;
}
//delete(dummy);
//dummy = nullptr;
return;
}
private:
Node *data[HASHTABLE_SIZE] = {
NULL};
};
/**
* Your MyHashMap object will be instantiated and called as such:
* MyHashMap* obj = new MyHashMap();
* obj->put(key,value);
* int param_2 = obj->get(key);
* obj->remove(key);
*/
以下は、純粋な C スタイルの malloc バージョンです。
#define HASHTABLE_SIZE 1001
struct Node {
int key;
int value;
Node *next;
};
class MyHashMap {
public:
MyHashMap() {
}
void put(int key, int value) {
int newKey = key % HASHTABLE_SIZE;
if (data[newKey] == NULL) {
data[newKey] = (Node *)malloc(sizeof(Node));
data[newKey]->key = key;
data[newKey]->value = value;
data[newKey]->next = NULL;
} else {
Node *head = data[newKey], *p = head;
while (p) {
if (p->key == key) {
p->value = value;
return;
}
p = p->next;
}
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->key = key;
newNode->value = value;
newNode->next = data[newKey];
data[newKey] = newNode;
}
}
int get(int key) {
int newKey = key % HASHTABLE_SIZE;
if (data[newKey] == NULL) return -1;
Node *head = data[newKey], *p = head;
while (p) {
if (p->key == key) {
return p->value;
}
p = p->next;
}
return -1;
}
void remove(int key) {
int newKey = key % HASHTABLE_SIZE;
if (data[newKey] == NULL) return;
Node *head = data[newKey];
Node *dummy = (Node *)malloc(sizeof(Node));
dummy->next = head;
Node *prev = dummy, *p = head;
while (p) {
if (p->key == key) {
prev->next = p->next;
p->value = -1; //It is not necessary here. For remove, the node is actually deleted; set it as -1 to pass the test
//delete(p);
//p = nullptr;
return;
}
p = p->next;
}
//delete(dummy);
//dummy = nullptr;
return;
}
private:
Node *data[HASHTABLE_SIZE] = {
NULL};
};
/**
* Your MyHashMap object will be instantiated and called as such:
* MyHashMap* obj = new MyHashMap();
* obj->put(key,value);
* int param_2 = obj->get(key);
* obj->remove(key);
*/