题源
知识点
- 哈希表
- 对于哈希表,我有了新认识,以前我感觉
哈希是哈希,数组是数组
,虽然现在我也是这样理解的;但是我发现哈希表也是通过索引来查找的,和数组的查找差不多,只不过数组中的索引只能是大于登录0的整数
,而哈希表中即可以满足大于登录0的整数的数组特性,还可以是其他类型的数
。哈希中的索引是通过哈希算法得到的。
- 对于哈希表,我有了新认识,以前我感觉
- 排序
- 对于这道题目来说,排序也至关重要,因为解决此题,遍历的顺序尤为重要。而这里排序的是哈希的键,而非输入的数组。
思路
- 这一题其实也就是问,能不能分成n/2对的元素,且每一对的元素相差一倍即(value1 = 2 * value2)
- 思路
- 先将
数组转化为哈希表
。 - 单独考虑
哈希表中0的个数
是否符合条件。- 如果0的个数为
奇数
,则不满足条件返回假(false)
。 - 如果0的个数为
偶数
,则满足条件,继续执行
下面的代码。
- 如果0的个数为
- 对哈希表中的key进行
绝对值的排序
。 - 对拍好序的哈希表中的
key进行遍历
。- 如果哈希表中的key的个数
大于
哈希表中的2 *key 的个数则返回假(false)
。 - 哈希表中的2 *key的个数
等于
哈希表中的2 *key的个数减哈希表中的key的个数。
- 如果哈希表中的key的个数
- 成功遍历成功,
返回真(true)
。
- 先将
代码
python
- 第一个是直接用字典写的,第二个是用collections模块中的Counter写的。
- python写代码过程的总结:
- 字典用此方式
[key]
访问一个没有存在的key的值会报错
。 .get(key)
方法访问一个没有存在的key的值默认返回None,如果需要更改默认返回需加第二个参数,如默认返回1
,.get(key, 1)
。- .setdefault(key, value)设置key的默认值为value,如果改字典存在该key,则此方法失效。
- collections模块中的Counter(arr)就是统计arr中元素的个数。并且可以通过
[key]
访问,并且就算访问一个没有存在的key的值也不会报错
,默认返回0
。
- 字典用此方式
class Solution:
def canReorderDoubled(self, arr: list[int]) -> bool:
arr_dict = self.arrToDict(arr) # 将数组转换为字典或者说是哈希化
if arr_dict.get(0, 0) % 2 == 1:# 单独判断数组中0的个数
return False
for key in sorted(arr_dict, key=abs):
if arr_dict.get(key, 0) > arr_dict.get(2 * key, 0):
return False
arr_dict[2 * key] = arr_dict.get(2 * key, 0) - arr_dict.get(key, 0)
return True
def arrToDict(self, arr: list[int]) -> list[int]:
re = {}
for num in arr:
re.setdefault(num, 0)
re[num] += 1
return re
执行用时:104 ms, 在所有 Python3 提交中击败了79.72%的用户
内存消耗:17.1 MB, 在所有 Python3 提交中击败了37.06%的用户
import collections as cs
class Solution:
def canReorderDoubled(self, arr: List[int]) -> bool:
arr_dict = cs.Counter(arr)
if arr_dict[0] % 2 == 1:
return False
for key in sorted(arr_dict, key=abs):
if arr_dict[key] > arr_dict[2 * key]:
return False
arr_dict[2 * key] -= arr_dict[key]
return True
执行用时:100 ms, 在所有 Python3 提交中击败了79.72%的用户
内存消耗:17 MB, 在所有 Python3 提交中击败了50.35%的用户
javascript
- javascript写代码过程的总结:
- Map()和对象的差异
Map.prototype.get或者set
会重写
默认的方法,并且遍历的时候不会出现重写的方法,如果你Map.prototype.asd等自定义
的方法时候,你通过for in 遍历map的时候会把自定义的方法命遍历出来
。- map和对象访问
不存在的key
时,不会报错,而是会返回undefined
。
/**
* @param {number[]} arr
* @return {boolean}
*/
var canReorderDoubled = function(arr) {
let arrMap = arrToMap(arr)
if(arrMap.get(0) % 2 === 1) return false
for(let key of mapSort(arrMap)){
if(arrMap.get(key) > arrMap.get(2 * key)) return false
arrMap[2 * key] = arrMap.get(2 * key) - arrMap.get(key)
}
return true
};
const arrToMap = (arr) => {
let re = new Map()
Map.prototype.get = function(key){
if(this[key] === undefined) return 0
return this[key]
}
Map.prototype.set = function(key){
if(this[key] === undefined) this[key] = 1
else this[key]++
}
for(let num of arr) re.set(num)
return re
}
const mapSort = (map) =>{
let arr = []
for(let key in map) arr.push(key)
return arr.sort((a, b) => Math.abs(a) - Math.abs(b))
}
执行用时:124 ms, 在所有 JavaScript 提交中击败了60.00%的用户
内存消耗:47.8 MB, 在所有 JavaScript 提交中击败了60.00%的用户
java
- 对java确实不够熟悉,总共写了5次才过。
- java写代码过程的总结:
- if语句中只写一个
只能用布尔类型(真假)
,如果用其他类型则需要用运算符
(!=、==等)。 map.getOrDefault(key, defaultValue)
就是当key不存在时,返回defaultValue,存在则返回当前key的值。map.keySet()获取的键值
,需要重新赋值
给其他对象,如List集合,之后再进行相应的操作。Collections.sort(list, cmp)
进行排序。
- if语句中只写一个
class Solution {
public boolean canReorderDoubled(int[] arr) {
Map<Integer, Integer> map = Solution.arrToMap(arr);
if(map.getOrDefault(0, 0) % 2 == 1) return false;
List<Integer> list = new ArrayList<>();
for(int num : map.keySet()) list.add(num);
Collections.sort(list, (a, b) -> Math.abs(a) - Math.abs(b));
for(int key : list){
int key1Count = map.getOrDefault(key, 0);
int key2Count = map.getOrDefault(key * 2, 0);
if(key1Count > key2Count) return false;
map.replace(2 * key, key2Count - key1Count);
}
return true;
}
public static Map<Integer, Integer> arrToMap(int[] arr){
Map<Integer, Integer> map = new HashMap<>();
for(int key : arr){
if(map.containsKey(key)) map.replace(key, map.get(key) + 1);
else map.put(key, 1);
}
return map;
}
}
执行用时:28 ms, 在所有 Java 提交中击败了89.17%的用户
内存消耗:49.1 MB, 在所有 Java 提交中击败了10.30%的用户
C
- 对C哈希参考文献
- 仲一.C语言哈希表uthash的使用方法详解.知乎
- aclove.uthash详解.博客园
- Troy D. Hanson.uthash下载链接.github
- 对C的总结:
- 使用uthash中其实也是用了
双向链表
,故每一次添加map的地址都会变化
,故我写函数的时候,需要返回当前位置。 - 自己写的函数效率不高。
- 下面是uthash的常用方法。
- 使用uthash中其实也是用了
HASH_ADD_INT(map, key, temp); //key为你自己定义结构体key的名字,为添加的结构体temp
HASH_FIND_INT(map, &one, find); //找不到返回NULL
HASH_REPLACE_INT(map, key, newtemp1, temp); // 替换
HASH_DEL(map, newtemp1); // 删除
HASH_CLEAR(hh, map);// 清空
int HASH_COUNT(map) // 返回int类型,个数
HASH_SORT( users, name_sort ); // 排序
- 程序代码
typedef struct{ // C语言哈希结构体
int key;
int value;
UT_hash_handle hh; // 这个就是必写
}Map;
int get(Map *map, int key){ // get函数,如果存在则返回相应的int值,如果不存在则返回0
Map *result;
HASH_FIND_INT(map, &key, result);
if(result == NULL) return 0;
else return result->value;
}
bool find(Map *map, int key){ // find函数,存在则为true,不存在则返回false
Map *result;
HASH_FIND_INT(map, &key, result);
if(result == NULL) return false;
else return true;
}
Map* set(Map *map, int key, int value){ // set函数,设置键值
Map *add = (Map *)malloc(sizeof(Map));
add->key = key;
add->value = value;
if(find(map, key)){
Map *old = (Map *)malloc(sizeof(Map));
HASH_REPLACE_INT(map, key, add, old);
}
else HASH_ADD_INT(map, key, add);
return map;
}
Map* arrToMap(int *arr, int arrSize){ // 数组转化为map数据类型
Map* map = (Map *)malloc(sizeof(Map));
map = NULL;
for(int i = 0; i < arrSize; i++){
if(find(map, arr[i])) map = set(map, arr[i], get(map, arr[i]) + 1);
else map = set(map, arr[i], 1);
}
return map;
}
int *getKeys(Map *map, int *keysLen){ // 已数组形式返回哈希所有的键
int *arr = (int *)malloc(sizeof(int) * HASH_COUNT(map));
*keysLen = 0;
Map *temp;
for(temp = map; temp != NULL; temp = (Map *)temp->hh.next){
arr[(*keysLen)++] = temp->key;
}
return arr;
}
void mapPrintAll(Map *map){ // 遍历map的函数,在这道题目测试使用
Map *temp;
for(temp = map; temp != NULL; temp = (Map *)temp->hh.next){
printf("%d: %d\n", temp->key, temp->value);
}
}
int cmp(const void *a, const void *b){ // qsort函数的比较函数
return abs(*((int *)a)) - abs(*((int *)b));
}
bool canReorderDoubled(int* arr, int arrSize){
Map* map = arrToMap(arr, arrSize);
int *keysLen = (int *)malloc(sizeof(int));
int *keys = getKeys(map, keysLen);
qsort(keys, *keysLen, sizeof(int), cmp);
for(int i = 0; i < *keysLen; i++){
if(get(map, keys[i]) > get(map, 2 * keys[i])) return false;
set(map, 2 * keys[i], get(map, 2 * keys[i]) - get(map, keys[i]));
}
return true;
}
执行用时:196 ms, 在所有 C 提交中击败了5.71%的用户
内存消耗:85.8 MB, 在所有 C 提交中击败了5.72%的用户