day06_LC学习计划:数据结构入门
作者:互联网
387.字符串中的第一个唯一字符
给定一个字符串 s ,找到 它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回 -1 。
示例 1:
输入: s = "leetcode"
输出: 0
示例 2:输入: s = "loveleetcode"
输出: 2
示例 3:输入: s = "aabb"
输出: -1
提示:
1 <= s.length <= 105
s 只包含小写字母来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/first-unique-character-in-a-string
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
一、idea:
简单思路,用int类型的一维数组充当哈希表进行标记每个字符出现过的数量,使用memset进行初始化,遇到一个字符就给这个哈希表中相应字符的数值+1,完成标记后再循环一遍字符串,当发现第一次发现出现次数是1的字符时便输出。
int firstUniqChar(char * s){
int hash[26],l=strlen(s);
memset(hash,0,sizeof(hash));
for(int i=0;i<l;i++){
int index=s[i]-'a';
hash[index]++;
}
for(int i=0;i<l;i++){
int index=s[i]-'a';
if(hash[index]==1){
return i;
}
}
return -1;
}
简单题我重拳出击[doge]!!
二、解法:
- 使用哈希表存储出现频次,思路和上述idea一致,只是代码使用了哈希表。
- 使用哈希表存储字符索引,如果出现了两次则把其索引改为-1,最后找到不是-1的最小索引。
- 组建队列,把遍历的字符串都构成哈希的二元组放入队列,遍历完字符串之后队首元素就是所要找的元素。
三、代码实现的细节学习:
1、简单地构建哈希表即可得到。
struct hashTable {
int key;
int val;
UT_hash_handle hh;
};
int firstUniqChar(char* s) {
struct hashTable* frequency = NULL;
int n = strlen(s);
for (int i = 0; i < n; i++) {
int ikey = s[i];
struct hashTable* tmp;
HASH_FIND_INT(frequency, &ikey, tmp);
if (tmp == NULL) {
tmp = malloc(sizeof(struct hashTable));
tmp->key = ikey;
tmp->val = 1;
HASH_ADD_INT(frequency, key, tmp);
} else {
tmp->val++;
}
}
for (int i = 0; i < n; i++) {
int ikey = s[i];
struct hashTable* tmp;
HASH_FIND_INT(frequency, &ikey, tmp);
if (tmp != NULL && tmp->val == 1) {
return i;
}
}
return -1;
}
2、其中用到了哈希表遍历的HASH_ITER函数,还不会用,学习一下。其中在HASH_ITER中的tmp变量还不知道其作用。
struct hashTable{
int key;
int val;
UT_hash_handle hh;
};
int firstUniqChar(char * s){
int len = strlen(s);
struct hashTable* map=NULL;
for(int i=0;i<len;i++){
int ikey = s[i];
struct hashTable* tmp;
HASH_FIND_INT(map,&ikey,tmp);
if(tmp==NULL){
tmp=malloc(sizeof(struct hashTable));
tmp->key=ikey;
tmp->val=i;
HASH_ADD_INT(map,key,tmp);
}else{
tmp->val=-1;
}
}
int first=len;
struct hashTable *iter,*tmp;
HASH_ITER(hh,map,iter,tmp){
int index = iter->val;
if(index!=-1 && index<first){
/*这里的index<first是为了保证如果某一个点的索引比它小就让返回值等于它*/
first=index;
}
}
if(first==len){
first=-1;
}
return first;
}
3、联合使用了队列和哈希表,C的队列使用一直是自己的弱项,学习一下。
struct hashTable{
int key;
int val;
UT_hash_handle hh;
};
int firstUniqChar(char * s){
int len=strlen(s);
struct hashTable* map=NULL;
int queue[26][2];
memset(queue,0,sizeof(queue));
int left=0,right=0;
for(int i=0;i<len;i++){
int ikey=s[i];
struct hashTable* tmp;
HASH_FIND_INT(map,&ikey,tmp);
if(tmp==NULL){
tmp=malloc(sizeof(struct hashTable));
tmp->key=ikey;
tmp->val=i;
HASH_ADD_INT(map,key,tmp);
queue[right][0]=ikey;
queue[right++][1]=i;
}else{
tmp->val=-1;
while(left<right){
int ikey=queue[left][0];
struct hashTable* tmp;
HASH_FIND_INT(map,&ikey,tmp);
if(tmp==NULL || tmp->val!=-1){
break;
}
left++;
}
}
}
return left<right?queue[left][1]:-1;
}
383.赎金信
给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。
如果可以,返回 true ;否则返回 false 。
magazine 中的每个字符只能在 ransomNote 中使用一次。
示例 1:
输入:ransomNote = "a", magazine = "b"
输出:false
示例 2:输入:ransomNote = "aa", magazine = "ab"
输出:false
示例 3:输入:ransomNote = "aa", magazine = "aab"
输出:true来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/ransom-note
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
一、idea:
用两个数组记录每个字符出现的次数,最后需要magazine数组中的字符出现次数要大于ransomNote数组。
bool canConstruct(char * ransomNote, char * magazine){
int hashA[26],hashB[26];
memset(hashA,0,sizeof(hashA));
memset(hashB,0,sizeof(hashB));
int rL=strlen(ransomNote),mL=strlen(magazine);
for(int i=0;i<rL;i++){
int index=ransomNote[i]-'a';
hashA[index]++;
}
for(int i=0;i<mL;i++){
int index=magazine[i]-'a';
hashB[index]++;
}
for(int i=0;i<26;i++){
if(hashA[i]>hashB[i]){
return false;
}
}
return true;
}
二、解法:
思路相同,但是答案的空间复杂度更低。
三、代码实现细节的学习:
自己使用了两个数组来保存两个数组的字符出现的次数,其实只需要保存ransomNote中的字符出现的数目,再循环magazine数组,循环过程中如果出现数组中的值小于1就可以返回false,否则可以返回true。
应先在数组中保存范围较大的数组,否则会出现小数组的范围无法cover大数组的问题,从而报错!所以本题中应先保存magazine数组,再保存ransomNote数组。
bool canConstruct(char * ransomNote, char * magazine){
int hash[26];
memset(hash,0,sizeof(hash));
int rL=strlen(ransomNote),mL=strlen(magazine);
for(int i=0;i<mL;i++){
int index=magazine[i]-'a';
hash[index]++;
}
for(int i=0;i<rL;i++){
int index=ransomNote[i]-'a';
hash[index]--;
if(hash[index]<0){
return false;
}
}
return true;
}
242.有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
示例 1:
输入: s = "anagram", t = "nagaram"
输出: true
示例 2:输入: s = "rat", t = "car"
输出: false
提示:
1 <= s.length, t.length <= 5 * 104
s 和 t 仅包含小写字母进阶: 如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/valid-anagram
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
一、idea:
按上题的idea修改成两个数组的字符数不相等则false,相等则true可以直接得到一个解。
二、解法:
- 排序
- 哈希表
三、代码实现的细节学习:
1、新学习strcmp函数。
strcmp函数是string compare(字符串比较)的缩写,用于比较两个字符串并根据比较结果返回整数。基本形式为strcmp(str1,str2),若str1=str2,则返回零;若str1<str2,则返回负数;若str1>str2,则返回正数。
判断两个字符串相等可以用排序后再进行对比,学到了。
int cmp(const void*_a,const void* _b){
return *(char*)_a-*(char*)_b;
}
bool isAnagram(char * s, char * t){
int lenS=strlen(s),lenT=strlen(t);
if(lenS!=lenT){
return false;
}
qsort(s,lenS,sizeof(char),cmp);
qsort(t,lenT,sizeof(char),cmp);
return strcmp(s,t)==0;
}
2、 方法核心也是遍历第一个字符串构建哈希表,然后遍历第二个字符串直到结束,如果哈希表中还有数字>0或者<0则可以返回false。并且解答中用长度不一致规避了如果出现某一个字符在第一个字符串中出现而在另一个串没有出现导致的错误。
C中记得初始化!记得初始化!记得初始化!
bool isAnagram(char * s, char * t){
int lenS=strlen(s),lenT=strlen(t);
if(lenS!=lenT){
return false;
}
int hash[26];
memset(hash,0,sizeof(hash));
for(int i=0;i<lenS;i++){
hash[s[i]-'a']++;
}
for(int i=0;i<lenT;i++){
hash[t[i]-'a']--;
if(hash[t[i]-'a']<0){
return false;
}
}
return true;
}
对于进阶问题,同样也是可以使用方法2构建哈希表进行处理。
标签:tmp,ransomNote,LC,int,day06,char,magazine,哈希,数据结构 来源: https://blog.csdn.net/weixin_57885126/article/details/123416272