前言
这是我开始刷算法题的第一天,所以会很生疏,用到的语言是JS
题目:力扣 3184. 构成整天的下标对数目 I
一、题目内容
给你一个整数数组 hours,表示以 小时 为单位的时间,返回一个整数,表示满足 i < j 且 hours[i] + hours[j] 构成 整天 的下标对 i, j 的数目。
整天 定义为时间持续时间是 24 小时的 整数倍 。
例如,1 天是 24 小时,2 天是 48 小时,3 天是 72 小时,以此类推。
示例 1: 输入: hours = [12,12,30,24,24] 输出: 2 解释: 构成整天的下标对分别是 (0, 1) 和 (3, 4)。
示例 2: 输入: hours = [72,48,24,3] 输出: 3 解释: 构成整天的下标对分别是 (0, 1)、(0, 2) 和 (1, 2)。
提示: 1 <= hours.length <= 100 1 <= hours[i] <= 109
二、我的解题方法
1.双重for循环(暴力解决)
代码如下(示例):
/**
* @param {number[]} hours
* @return {number}
*/
var countCompleteDayPairs = function (hours) {
let count = 0
for (let i = 0; i < hours.length; i++)
for (let j = i + 1; j < hours.length; j++)
if ((hours[i] + hours[j]) % 24 === 0 ) count++
return count
}
时间复杂度:O(n²) i*j
2.如何进一步优化这段代码的时间复杂度?
可以通过使用哈希表(在 JavaScript 中可以使用 Map 或普通对象来模拟哈希表)来优化代码,将时间复杂度从嵌套循环的 O(n²)降低到 O(n)。
具体思路是:遍历数组 hours,对于每个元素 hours[i],计算出它与 24 的余数 rem,然后检查哈希表中是否已经存在 24 - comp(如果 rem为 0,则检查 0 是否存在)。如果存在,说明找到了可以构成整天的一对数,将对应的计数加到结果中。同时,将当前元素的余数作为键,在哈希表中记录其出现的次数。 以下是优化后的代码:
/**
* @param {number[]} hours
* @return {number}
*/
var countCompleteDayPairs = function (hours) {
const hash = {}; // 哈希表用于记录余数出现的次数
let count = 0;
for (const num of hours) {
const rem = num % 24; // rem余数
const comp = (24 - rem) % 24; // comp:和余数凑对的另一个余数
count += hash[comp] || 0; // 每次循环将另一个余数出现的次数加上
hash[rem] = (hash[rem] || 0) + 1; // 每次循环都要将之前遍历过的都加到哈希表里面
}
return count;
}
在这段代码中: 1、首先创建一个空的 Map 用于存储余数及其出现的次数。 2、遍历 hours 数组,计算每个元素除以 24 的余数 rem。 3、确定需要查找的目标余数 comp,如果 rem为 0,则 comp 也为 0;否则 comp为 24 - rem。 4、检查哈希表中是否存在 targetRemainder,如果存在,则将其出现的次数加到 count 中。 5、将当前余数 rem作为键,在哈希表中记录其出现的次数(如果不存在则初始化为 0 再加1)。 6、最后返回 count 作为满足条件的下标对的数目。 这样,通过使用哈希表,代码的时间复杂度降低到了 O(n),其中 n 是数组 hours 的长度。
3、什么是哈希表
哈希表(Hash Table),也称为散列表,是一种数据结构,它可以提供快速的查找、插入和删除操作。以下是关于哈希表的详细介绍:
1、基本原理:哈希表通过一个哈希函数将键值(Key)映射到一个固定大小的数组中,这个数组被称为哈希数组或桶数组。当要存储一个键值对时,先通过哈希函数计算出键的哈希值,然后根据哈希值确定在哈希数组中的存储位置,将值存储在该位置。当需要查找某个键对应的值时,同样使用哈希函数计算键的哈希值,然后直接到对应的位置去获取值,这样可以在较短时间内完成查找操作。 2、哈希函数:它是哈希表的核心组成部分,其作用是将任意长度的键值转换为固定长度的哈希值。好的哈希函数应该具有以下特点:计算高效,能够快速地计算出哈希值;均匀分布,尽可能使不同的键值均匀地分布在哈希数组中,减少哈希冲突的发生。例如,常见的哈希函数有取余法、乘法哈希法等。 3、哈希冲突:当不同的键值通过哈希函数计算出相同的哈希值时,就会发生哈希冲突。解决哈希冲突的方法有多种,常见的有链地址法和开放寻址法。链地址法是将发生冲突的键值对存储在一个链表中,该链表挂在哈希数组的对应位置上。开放寻址法是当发生冲突时,通过一定的探测策略在哈希数组中寻找下一个可用的位置来存储键值对。 4、优点: 快速查找:在理想情况下,哈希表的查找、插入和删除操作的时间复杂度都可以达到 O(1),这使得它在处理大量数据时具有很高的效率。 灵活使用:可以根据实际需求选择不同的哈希函数和解决冲突的方法,以适应不同的应用场景。 5、缺点: 空间开销:为了减少哈希冲突,哈希表通常需要分配一定的额外空间,这可能会导致空间利用率不高。 哈希函数选择:如果哈希函数选择不当,可能会导致哈希冲突频繁发生,从而降低哈希表的性能。
哈希表在很多场景中都有广泛的应用,如数据库索引、缓存系统、编译器中的符号表等,是一种非常重要的数据结构。