⭐算法入门⭐《哈希表》中等02 —— LeetCode 560. 和为K的子数组
Posted 英雄哪里出来
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了⭐算法入门⭐《哈希表》中等02 —— LeetCode 560. 和为K的子数组相关的知识,希望对你有一定的参考价值。
🙉饭不食,水不饮,题必须刷🙉
C语言免费动漫教程,和我一起打卡! 🌞《光天化日学C语言》🌞
LeetCode 太难?先看简单题! 🧡《C语言入门100例》🧡
数据结构难?不存在的! 🌳《画解数据结构》🌳
LeetCode 太简单?算法学起来! 🌌《夜深人静写算法》🌌
一、题目
1、题目描述
给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。
样例输入:s = nums = [1,1,1], k = 2
样例输出:2
2、基础框架
- C语言版本 给出的基础框架代码如下:
int subarraySum(int* nums, int numsSize, int k){
}
3、原题链接
( 1 ) (1) (1) LeetCode 560. 和为K的子数组
( 2 ) (2) (2) 剑指 Offer II 010. 和为 k 的子数组
二、解题报告
1、思路分析
1)考虑一段连续子数组,左区间为
i
i
i,右区间为
j
j
j,子数组区间和
s
(
i
,
j
)
=
∑
t
=
i
j
n
u
m
s
[
t
]
s(i,j) = \\sum_{t=i}^{j} nums[t]
s(i,j)=∑t=ijnums[t];
2)令前缀和
s
u
m
[
i
]
=
∑
j
=
0
i
n
u
m
s
[
j
]
sum[i] = \\sum_{j=0}^{i}nums[j]
sum[i]=∑j=0inums[j],利用部分和公式,得到
s
(
i
,
j
)
=
s
u
m
[
j
]
−
s
u
m
[
i
−
1
]
s(i,j) = sum[j] - sum[i-1]
s(i,j)=sum[j]−sum[i−1] 3)根据题意,需要满足
k
=
s
u
m
[
j
]
−
s
u
m
[
i
−
1
]
k = sum[j] - sum[i-1]
k=sum[j]−sum[i−1],移项后得到
s
u
m
[
j
]
=
s
u
m
[
i
−
1
]
+
k
sum[j] = sum[i-1] + k
sum[j]=sum[i−1]+k 4)于是,我们可以通过枚举
s
u
m
[
j
]
sum[j]
sum[j],然后查找有多少满足条件的
s
u
m
[
i
]
+
k
(
−
1
≤
i
<
j
)
sum[i]+k \\ (-1 \\le i \\lt j)
sum[i]+k (−1≤i<j),统计求和。再把
s
u
m
[
j
]
+
k
sum[j] + k
sum[j]+k 进行插入供下次查找用。这里的插入查找,只需要维护一个哈希表即可。
2、时间复杂度
- 哈希表的插入查找均摊复杂度为 O ( 1 ) O(1) O(1),总共 n n n 个数字的枚举,时间复杂度为 O ( n ) O(n) O(n)。
3、代码详解
/******************** 哈希表 开放定址法 ********************/
#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; // 除留余数法
}
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;
}
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;
}
/******************** 哈希表 开放定址法 ********************/
#define maxs 20020
int sum[maxs];
int cnt[maxn];
HashTable ht;
int subarraySum(int* nums, int numsSize, int k){
int i, pos, ans;
for(i = 0; i < numsSize; ++i) {
sum[i] = nums[i];
if(i)
sum[i] += sum[i-1]; // (1)
}
ans = 0;
memset(cnt, 0, sizeof(cnt));
HashInit( &ht );
pos = HashInsert( &ht, k ); // (2)
++cnt[ pos ];
for(i = 0; i < numsSize; ++i) {
if( HashSearchKey( &ht, sum[i], &pos) ) {
ans += cnt[ pos ]; // (3)
}
++cnt[ HashInsert( &ht, sum[i] + k ) ]; // (4)
}
return ans;
}
- ( 1 ) (1) (1) 计算前缀和;
-
(
2
)
(2)
(2) 首先将
sum[-1] + k
插入到哈希表; -
(
3
)
(3)
(3) 如果哈希表中存在
sum[i]
这个关键字,则它的统计个数; -
(
4
)
(4)
(4) 将
sum[i]+k
插入哈希表,供下次查找使用;
三、本题小知识
哈希表 执行插入前 要先判断是否存在这个关键字。
以上是关于⭐算法入门⭐《哈希表》中等02 —— LeetCode 560. 和为K的子数组的主要内容,如果未能解决你的问题,请参考以下文章
⭐算法入门⭐《哈希表》中等04 —— LeetCode 347. 前 K 个高频元素
⭐算法入门⭐《哈希表》中等03 —— LeetCode 380. O 时间插入删除和获取随机元素
⭐算法入门⭐《哈希表》中等05 —— LeetCode 215. 数组中的第K个最大元素