问题1描述
给定一个长度为 n
的整数数组 nums
,数组中的数的范围是 [1, 100]
。请返回 nums
中出现一次的数的和。
问题1方法
1.可以用长度为101个的哈希表,下标i的位置对应存储数组nums中下标i出现的次数
给定 nums = [1, 2, 1, 3, 4]
:
- 数字
1
出现了2
次。 - 数字
2
出现了1
次。 - 数字
3
出现了1
次。 - 数字
4
出现了1
次。
则在哈希表中 - 下标为1的位置存储2
- 下标为2的位置存储1
- 下标为3的位置存储1
- 下标为4的位置存储1
hash:[0,2,1,1,1]
2.遍历完nums数组后,找到hash表中值为1的下标
问题1代码
int sumOFUnique(int* nums,int n){
int hash[101];
int i,sum=0;
memset(hash,0,sizeof(hash));
//初始化hash表中的数全为0
for(i=0;i<n;++i){
++hash[nums[i]];
}
for(i=0;i<n;=+i){
if(hash[nums[i]==1){
sum+=nums[i];
}
}
return sum;
]
问题2描述
给定一个长度为 2n
的整数数组 nums
,数组中的数的范围是 [1, 500]
。判断是否可以将它们划分成 n
个数对,满足以下条件:
- 每个数只属于一个数对。
- 同一数对中的元素相等。
示例
输入: nums = [1, 2, 2, 1]
输出: True
(可以划分成两对:(1, 1) 和 (2, 2))
算法步骤
-
初始化一个空的哈希表
countMap
用于存储对应下标的数字出现的次数。 -
遍历数组
nums
,对于每个元素num
:- 如果
countMap
中没有num
,则添加num
到countMap
并设置其计数为 1。 - 如果
countMap
中已有num
,则将其计数加 1。
- 如果
-
再次遍历
countMap
,检查每个数字的计数:- 如果任何数字的计数不是偶数,则返回
False
,因为这意味着无法将所有数字配对。 - 如果所有数字的计数都是偶数,则返回
True
- 如果任何数字的计数不是偶数,则返回
-
如果所有数字的计数都是偶数,继续检查是否可以将它们配对:
- 初始化一个布尔数组
visited
,长度为501
(因为数组中的数的范围是[1, 500]
),所有元素初始值为false
。 - 遍历数组
nums
,对于每个元素num
:- 如果
visited[num]
为true
,则表示num
已经配对,继续检查下一个元素。 - 如果
visited[num]
为false
,则将visited[num]
设置为true
并尝试寻找配对:- 从当前索引
i
开始,向后遍历数组,寻找下一个相同的num
。 - 如果找到,则将
visited[num]
对应的两个位置都设置为true
,表示这两个num
已经配对。 - 如果在数组末尾之前没有找到配对的
num
,则返回False
。
- 从当前索引
- 如果
- 初始化一个布尔数组
-
如果所有元素都成功配对,返回
True
。
代码
bool divideArray(int* nums,int numsSize){
int i,hash[501];
memset(hash,0,sizeof(hash));
for(i=0;i<numsSize,++i){
++hash[nums[i]];
//哈希表对应下标的数字出现一次+1
}
for(i=1;i<=500;++i){
if(hash[i]&1){
return false;
}//如果发现其中有奇数次说明肯定不能配对成功,返回false
}
return true;
}
在编程中,&
是按位与(bitwise AND)操作符。当你对两个数进行按位与操作时,结果的每一位都是由对应的两位决定的,如果对应的两位都是1,那么结果位就是1,否则就是0。
对于表达式 hash[i] & 1
:
- 如果
hash[i]
的二进制表示的最低位(即个位)是1,那么hash[i] & 1
的结果就是1。 - 如果
hash[i]
的最低位是0,那么hash[i] & 1
的结果就是0。
在整数中,如果一个数的最低位是1,那么这个数就是奇数;如果最低位是0,那么这个数就是偶数。因此,hash[i] & 1
可以用来判断 hash[i]
是否为奇数:
- 如果
hash[i] & 1
等于1,那么hash[i]
是奇数。 - 如果
hash[i] & 1
等于0,那么hash[i]
是偶数。
这种按位操作通常用于优化,因为它比除以2并取余数(% 2
)的操作要快,尤其是在处理大量数据时。
复杂度分析
- 时间复杂度:O(n),其中 n 是数组
nums
的长度。我们只遍历了数组两次。 - 空间复杂度:O(1),除了输入数组外,我们只使用了固定大小的额外空间。
注意事项
- 确保在寻找配对时,不要重复使用已经配对的元素。
- 在实际编程实现中,需要考虑数组索引的边界条件,避免越界错误。
问题3描述
给定一个仅由小写英文字母组成的字符串,判断它是否是全字母句。全字母句定义为字符串中包含英文字母表中的每一个字母至少一次。
示例
输入: sentence = "adcbacbf"
输出: False
(因为字符串中缺少字母 ‘e’, ‘g’, ‘h’, ‘i’, ‘j’, ‘k’, ‘l’, ‘m’, ‘n’, ‘o’, ‘p’, ‘q’, ‘r’, ‘s’, ‘t’, ‘u’, ‘v’, ‘w’, ‘x’, ‘y’, ‘z’ 中的一些)
算法步骤
因为字母-》ASCII码值(字母可以转换为ASCII码值且<=256)
- 创建一个长度为26的布尔数组
letterFound
,用于标记26个英文字母是否都出现过,初始值全部为false
。 - 遍历字符串
sentence
中的每个字符char
:- 计算
index = char - 'a'
,得到字符在字母表中的索引。 - 将
letterFound[index]
设置为true
,表示该字母已经出现过。
- 计算
- 再次遍历
letterFound
数组:- 如果发现任何元素为
false
,则说明有字母未在sentence
中出现,返回False
。 - 如果所有元素都为
true
,则说明sentence
是全字母句,返回True
。
- 如果发现任何元素为
代码
bool checkIfPangram(char *sentence){
int i,hash[256];
memset(hash,0,sizeof(hash));
for(i=0;sentence[i];++i){
++hash[sentence[i]];
}//对每个字符进行计数,一直到句子结束,将字符转为ASCII码值存入hash表中
for(i='a';i<='z';++i){
//遍历每个小写字母
if(!hash[i]){//如果哈希表中 其中一个字母转为ASCII码值的下标处=0,说明这个字母没有出现过
return false;
}
}
return true;//否则返回true
}
}
复杂度分析
- 时间复杂度:O(n),其中 n 是字符串
sentence
的长度。我们只遍历了字符串两次。 - 空间复杂度:O(1),我们使用了一个固定大小的数组来存储字母的出现情况。
注意事项
- 确保字符的比较是基于字母表的索引,而不是字符的ASCII值。
- 在实际编程实现中,注意字符 ‘a’ 的ASCII值是97,而不是0,因此在计算索引时要减去 ‘a’ 的ASCII值。