一、基本知识
1.双指针
通常可以用两个指针来判断一个字符串是不是回文,要么两个指针从字符串的两端开始向中间移动,要么两个指针从中间开始向两端移动。
2.哈希表:
如果题目强调字符串只包含英文小写字母,可以使用数组模拟一个简单的哈希表。
3.变位词:指组成各个单词的字母及每个字母出现的次数完全相同,只是字母排列的顺序不同。
通常可以用一个哈希表来统计每个字符出现的次数,有了哈希表就很容易判断两个字符串是不是一组变位词。
二、题目
1.字符串中的变位词
思路:哈希表+双指针(当哈希表中的值都为0时为true)
tips:在函数中无法获取数组长度,使用sizeof只能获取形参的大小,要实现获得数组长度,需要在函数中增加参数。
bool allZero(int* arr, int arrSize);
bool checkInclusion(char * s1, char * s2){
int s1Len = strlen(s1);
int s2Len = strlen(s2);
if(s2Len<s1Len)
return false;
int hash[26] = {0};
for(int i=0;i<s1Len;i++)
{
hash[s1[i]-'a']++;
hash[s2[i]-'a']--;
}
if(allZero(hash,26))
return true;
for(int i = s1Len;i<s2Len;i++)
{
hash[s2[i] - 'a']--;
hash[s2[i-s1Len] - 'a']++;
if(allZero(hash,26))
return true;
}
return false;
}
bool allZero(int* arr, int arrSize)
{
for(int i=0;i<arrSize;i++)
{
if(arr[i] != 0)
return false;
}
return true;
}
2.字符串中的所有变位词
思路:用字符串s1构造哈希表,之后用双指针在s2中移动,判断子串是否符合题意。
头脑风暴:尝试使用使用布尔值构造哈希表,失败,因为会出现子串中出现两个d,指针移走后边上的d移走变为false,但是子串中仍存在d,应该仍为true。就是说不能用简单的true和false记录,哈希表应该记录出现个数。
bool allZero(int* arr, int arrSize);
int* findAnagrams(char * s, char * p, int* returnSize){
int sLen = strlen(s);
int pLen = strlen(p);
int hash[26] = {0};
int* ret = (int*)malloc(sLen*sizeof(int));
int retLen = 0;
memset(ret,0,sLen*sizeof(int));
if(sLen < pLen)
{
*returnSize = 0;
return NULL;
}
for(int i=0;i<pLen;i++)
{
hash[p[i] - 'a']++;
hash[s[i] - 'a']--;
}
if(allZero(hash,26))
ret[retLen++] = 0;
for(int i=pLen;i<sLen;i++)
{
hash[s[i] - 'a']--;
hash[s[i-pLen] - 'a']++;
if(allZero(hash,26))
ret[retLen++] = i-pLen+1;
}
*returnSize = retLen;
return ret;
}
bool allZero(int* arr, int arrSize)
{
for(int i=0;i<arrSize;i++)
{
if(arr[i] != 0)
return false;
}
return true;
}
3.不含重复字符的最长子字符串
思路:哈希表+滑窗
int lengthOfLongestSubstring(char * s){
if(s == NULL)
return NULL;
int hash[256] = {0};
int len = strlen(s);
int left = 0;
int ret = 0;
for(int right = 0;right<len;right++)
{
hash[s[right]]++;
while(left<=right && hash[s[right]] == 2)
{
hash[s[left]]--;
left++;
}
ret = fmax(ret,right-left+1);
}
return ret;
}
4.包含所有字符的最短字符串
思路:双哈希表,当s的哈希值大于t的哈希值时左指针移动
char * minWindow(char * s, char * t){
int sLen = strlen(s);
int tLen = strlen(t);
if(sLen<tLen)
return "";
int tHash[256] = {0};
int sHash[256] = {0};
char* ret = (char*)malloc((sLen+1) * sizeof(char));
int left = 0;
int cnt = 0;
int minbegin = 0;
int minend = sLen;
for(int i=0;i<tLen;i++)
{
tHash[t[i]]++;
}
for(int right=0;right<sLen;right++)
{
sHash[s[right]]++;
if(sHash[s[right]] <= tHash[s[right]])
cnt++;
while(left<=right && sHash[s[left]] > tHash[s[left]])
{
sHash[s[left]]--;
left++;
}
if(cnt == tLen && right-left+1 < minend-minbegin+1)
{
minend = right;
minbegin = left;
}
}
int retLen = minend-minbegin+1;
if(retLen == sLen+1)
return "";
memcpy(ret,&s[minbegin],retLen);
ret[retLen] = '\0';
return ret;
}
5.有效回文
知识:
isalnum() 函数用来检测一个字符是否是字母或者十进制数字。
如果仅仅检测一个字符是否是字母,可以使用 isalpha() 函数;
如果仅仅检测一个字符是否是十进制数字,可以使用 isdigit() 函数。
tolower()函数:将大写字母转换为小写字母
toupper()将小写字母转换为大写字母
注意:为了防止指针错过或者数组越界,while判断使用的是if-elseif而不都是if
bool isPalindrome(char * s){
if(s == NULL)
return false;
int left = 0;
int right = strlen(s) - 1;
while(left <= right)
{
if(!isalnum(s[left]))
left++;
else if(!isalnum(s[right]))
right--;
else if(tolower(s[left]) == tolower(s[right]))
{
left++;
right--;
}
else
return false;
}
return true;
}
6.最多删除一个字符得到回文
思路:由于实现不知道应该删除两个不同字符中的哪一个,因此两个字符都可以进行尝试
bool isPalindrome(char* s,int left,int right);
bool validPalindrome(char * s){
if(s == NULL)
return false;
int sLen = strlen(s);
int left = 0;
int right = sLen-1;
while(left<=right)
{
if(s[left] == s[right])
{
left++;
right--;
}
else
return isPalindrome(s,left+1,right) | isPalindrome(s,left,right-1);
}
return true;
}
bool isPalindrome(char* s,int left,int right)
{
while(left<=right)
{
if(s[left] == s[right])
{
left++;
right--;
}
else
return false;
}
return true;
}
7.回文字符串的个数
思路一:中心拓展(考虑奇偶)
思路二:马拉车 算法详解
中心扩展法的实现(马拉车太难了呜呜呜)
int countPalindrome(char* s,int start,int end,int len);
int countSubstrings(char * s){
int len = strlen(s);
int ret = 0;
for(int i=0;i<len;i++)
{
ret += countPalindrome(s,i,i,len);
ret += countPalindrome(s,i,i+1,len);
}
return ret;
}
int countPalindrome(char* s,int start,int end,int len)
{
int count = 0;
while(start>=0 && end<len && s[start] == s[end])
{
start--;
end++;
count++;
}
return count;
}