1,求字符串中第一个只出现一次的字符:第一个只出现一次的字符_牛客题霸_牛客网 (nowcoder.com)
由于字符在计算机中归根结底是由阿斯克码所代表的,因此可以创建一个数组,每一个字符出现的次数就放在数组中其阿斯克码所对应的下标位置,到时候,从第一个字符对应的阿斯克码的下标开始寻找,找到的第一个元素为1的字符即为想要找的字符。
注:这里第二个for循环中,在创建的table数组中,是按照字符出现的顺序在数组中寻找字符出现的顺序的。获得数组中存储的每一个字符出现次数,还可以从1到128依次遍历,但是这两种方法在不同的题目中可能会出现不同的效果,这一点在做题的时候需要注意。比如本题,如果从1到128那样去找,确实可以找到只出现一次的字符,但是这个字符不一定是在字符串中第一个出现的,它只是在阿斯克码中最靠前且仅出现一次的字符。
int FirstNotRepeatingChar(char* str)
{
char table[128] = { 0 };
int len = strlen(str);
for (int i = 0; i < len; i++)//遍历整个字符串
{
table[str[i]] = table[str[i]] + 1;//每读到一个字符,就会将table数组中这个字符的阿斯克码
//对应的位置上的元素+1,即这个下标数字对应的阿斯克码所对应的字符又多了一个,字符串中不同的下标处对应的字符可能相同,这种情况下str[i]就可能等于str[j],而table[str[i]]与table[str[j]]对应的就是table数组中的同一位置。
}
for (int j = 0; j < len; j++)
{//str[j]本来是一个字符,即字符串中的第j+1个字符,但是当字符str[j]出现在数组table的括号
//中时,就由字符变成了字符对应的阿斯克码值。
if (table[str[j]] == 1)//如果这个字符只出现一次
{
return j;
}
}
return-1;
}
2,判定字符串中出现的字符是否唯一:面试题 01.01. 判定字符是否唯一 - 力扣(LeetCode) (leetcode-cn.com)
本题与上一题异曲同工,唯一的区别是第六题看的是table数组中的哪一个元素等于1,而本题看的是table数组中是否有元素大于1。
注:对于本题而言,第一题中提到的两种遍历方式都是可以使用的。(可以这样理解,本题的要求比较少,不矫情)
bool isUnique(char* astr)
{
char table[128]={0};
int i=0;
int sz=strlen(astr);
for(i=0;i<sz;i++)
{
table[astr[i]]=table[astr[i]]+1;
}
int j=0;
for(j=0;j<sz;j++)
{
if(table[astr[j]]>1)
{
return false;
}
}
return true;
}
3,给定两个字符串,判断一个字符串经过重新排列后能否变成另一个字符串。
面试题 01.02. 判定是否互为字符重排 - 力扣(LeetCode) (leetcode-cn.com)
这三道题的核心思想都是相同的。本题相当于把同一种思想用了两遍,分别找出两个字符串中各个元素的数量,然后将二者进行比较即可。
bool CheckPermutation(char*s1,char*s2)
{
int table1[128]={0},table2[128]={0};
int len1=strlen(s1);
int len2=strlen(s2);
if(len1!=len2)
{
return false;
}
int i=0;
int j=0;
while(i<len1)
{
table1[s1[i]]+=1;
i++;
}
while(j<len2)
{
table2[s2[j]]+=1;
j++;
}
for(int m=0;m<128;m++)
{
if(table1[m]!=table2[m])
{
return false;
}
}
return true;
}
4,判断字符串是否构成回文排列:
面试题 01.04. 回文排列 - 力扣(LeetCode) (leetcode-cn.com)
解这道题的关键思想和上面三道题一样。具体的思路是如果一个字符串在重新排列之后可以排列成回文形式,那么分两种情况,字符串中有偶数个字符、字符串中有奇数个字符。在有偶数个字符时,需要字符串中出现的每一种字符都出现偶数次才行。如果偶数个字符组成的字符串中某一种字符出现了奇数次,那么一定至少还有另一种字符也出现了奇数次。当字符串中有偶数个字符时,需要有且仅有一种字符出现奇数次,当这种情况发生时,其它出现的字符一定恰好都出现偶数次。综合分析以上两种情况,偶数个字符组成的字符串中,出现奇数次的字符在不就没有,(这时是回文结构,而由偶数个字符组成的字符串中,只要有一个元素出现奇数次,那这个字符串就一定不是回文结构)再不就出现一对、两对……,而奇数个字符组成的字符串中,出现奇数次的字符再不就出现一次,(这时是回文结构,需要注意的是,奇数个字符组成的字符串中不可能没有字符出现奇数次)再不就出现三次、五次……,那么在总结出规律后,我就不需要考虑字符串中有奇数个字符还是偶数个字符了,我只需要计算字符串中出现奇数次的字符一共有几种就可以了,只要小于一次,不管是1次还是0次,都一定是回文结构,只要大于一次,就一定不是回文结构。
bool canPermutePalindrome(char* s)
{
int table[128] = { 0 };
int sz = strlen(s);
int i = 0;
for (i = 0; i < sz; i++)
{
table[s[i]] += 1;
}
int m = 0;
int n = 0;
for (m = 0; m < 128; m++)
{
if (table[m] % 2 != 0)
{
n++;
}
if (n > 1)
{
return false;
}
}
return true;
}
注:对于本题而言,使用按照字符在字符串中出现的顺序来遍历就会出现问题。当字符串中有多个元素反复出现时,比如aaa,由于a出现了3次,那么table数组中a对应的为止就会为3,那此时程序会3次进入倒数第二个if语句中,无论是哪一个字符,只要它出现了奇数次,就会使n加1,设计这个程序的初衷本来是统计出现奇数次的不同种类的字符的种类数,但是,按照下面的程序跑起来,只要运行到出现奇数次的字符那里,就会导致n加1。这就会出现错误。
for (m = 0; m < sz - 1; m++)
{
if (table[s[m]] % 2 != 0)
{
n++;
}
if (n > 1)
{
return false;
}
}
5,判断一个字符串能否被另一个字符串所表示:
383. 赎金信 - 力扣(LeetCode) (leetcode-cn.com)
本题与前面几道题核心思想一致,但细节处略有不同。这道题的关键技巧是两个字符相减,得到的结果是一个数值,其大小等于两个字符的阿斯克码值的差。以后面对这类问题都可以通过两字符相减的方式,这样就可以用相减的结果作为下标存储该元素的个数。
bool canConstruct(char* ransomNote, char* magazine)
{
int a[26] = { 0 };
int i = strlen(ransomNote);
int j = strlen(magazine);
int m = 0;
int n = 0;
if (i <= j)//如果ransomNote字符串中的字符个数大于magazine字符串中的字符个数,那ransomNote字符串一定不能被magazine字符串表示
{
for (m = 0; m < j; m++)
{
a[magazine[m] - 'a']++;//两个字符相减等于它们的阿斯克码值相减,结果等于一个数,如果是两个小写字母相减的话,结果的范围在0~25之间
//通过这一步处理后,数组a中就存储了每一个字符出现的次数
}
for (n = 0; n < i; n++)
{
if (a[ransomNote[n] - 'a'] != 0)
{
a[ransomNote[n] - 'a']--;
}
else//如果比较完成之前(字符串还没有完成遍历之前)数组中的某个位置的值就等于0了,说明这个位置对应的字符不足以满足需求,即不能表示
{
return false;
}
}
return true;
}
else//ransomNote字符串中的字符个数大于magazine字符串中的字符个数,没必要判断了,直接返回错误
{
return false;
}
}