Leecode-187-重复的DNA序列
题目
DNA序列 由一系列核苷酸组成,缩写为 ‘A’, ‘C’, ‘G’ 和 ‘T’.。
例如,“ACGAATTCCG” 是一个 DNA序列 。
在研究 DNA 时,识别 DNA 中的重复序列非常有用。
给定一个表示 DNA序列 的字符串 s ,返回所有在 DNA 分子中出现不止一次的 长度为 10 的序列(子字符串)。你可以按 任意顺序 返回答案。
示例
示例1
输入:s = “AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT”
输出:[“AAAAACCCCC”,“CCCCCAAAAA”]
示例2
输入:s = “AAAAAAAAAAAAA”
输出:[“AAAAAAAAAA”]
解题思路
- 辅助函数:
- DNAHash* FindDna(char *s, int begin):从哈希表中查找从s的begin位置开始的长度为10的子串。如果找到,返回对应的DNAHash结构体指针;否则返回NULL。
- int GetDnaCnt(char *s, int begin):返回从s的begin位置开始的长度为10的子串在哈希表中出现的次数。
- void AddDna2Hash(char *s, int begin):将从s的begin位置开始的长度为10的子串添加到哈希表中。如果该子串已经存在,则增加其计数;否则,创建一个新的DNAHash结构体并添加到哈希表中。
- 主函数:
char ** findRepeatedDnaSequences(char * s, int* returnSize):这是主要的函数,用于查找并返回所有出现至少两次的、长度为10的连续子串。
· 首先,它计算了DNA字符串s的长度。
· 初始化一个结果数组result,用于存储找到的重复子串。
· 遍历字符串s,从每个可能的起始位置开始,长度为10的子串被添加到哈希表中。
· 如果某个子串的计数达到2(即它第二次出现),则将其添加到结果数组中。
· 在完成所有操作后,遍历哈希表并释放其占用的内存。
· 最后,返回结果数组并设置returnSize为结果数组中的子串数量。
代码实现
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
#define LEN 10
typedef struct DnaHash{
char dna[LEN + 1];
int cnt;
UT_hash_handle hh;
}DnaHash;
DnaHash* Dnahead = NULL;
DnaHash* FindDna(char* s,int begin){
DnaHash* flag = NULL;
char tmp[LEN+1] = {0};
strncpy(tmp, s + begin, LEN);
HASH_FIND_STR(Dnahead, tmp, flag);
return flag;
}
int GetDnaCnt(char *s, int begin){
DnaHash* tmp = FindDna(s, begin);
if(tmp != NULL){
return tmp->cnt;
}else{
return 0;
}
}
void AddDnaToHash(char *s,int begin){
DnaHash *tmp = FindDna(s, begin);
if(tmp == NULL){
tmp = (DnaHash *)malloc(sizeof(DnaHash));
memset(tmp, 0, sizeof(DnaHash));
strncpy(tmp->dna, s + begin, LEN);
tmp->cnt = 1;
HASH_ADD_STR(Dnahead, dna, tmp);
}else{
(tmp->cnt)++;
}
}
char ** findRepeatedDnaSequences(char * s, int* returnSize){
int len = strlen(s);
char **res = (char **)malloc(sizeof(char*)*len);
int cnt = 0;
for(int i = 0; i <= len - LEN; i++){
AddDnaToHash(s, i);
if(GetDnaCnt(s, i) == 2){
char* tmp = (char*)malloc(LEN + 1);
memset(tmp, 0, LEN + 1);
strncpy(tmp, s + i, LEN);
res[cnt++] = tmp;
}
}
DnaHash* pPrev = NULL;
DnaHash* pCurrent = NULL;
HASH_ITER(hh, Dnahead, pPrev, pCurrent) {
HASH_DEL(Dnahead, pPrev);
free(pPrev);
}
Dnahead = NULL;
*returnSize = cnt;
return res;
}
Leecode-1047-删除字符串中的所有相邻重复项
题目
给出由小写字母组成的字符串 S,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
示例
输入:“abbaca”
输出:“ca”
解释:
例如,在 “abbaca” 中,我们可以删除 “bb” 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 “aaca”,其中又只有 “aa” 可以执行重复项删除操作,所以最后的字符串为 “ca”。
解题思路
-
初始化res为输入字符串s的第一个字符,并设置索引index为1,准备写入下一个字符。
-
遍历s中的每一个字符,从第二个字符开始(因为第一个字符已经放在res中了)。
-
对于s中的每一个字符,检查它是否与前一个放入res的字符相同。如果不同,或者res为空(即index为0),则将其放入res中,并增加index。
-
如果s中的当前字符与res的最后一个字符相同,则将index减1,这样res中的最后一个字符就被覆盖了,相当于去除了重复字符。
-
最后,在res的index位置加上字符串结尾的’\0’。
-
返回res,这是去除连续重复字符后的结果字符串。
代码实现
char* removeDuplicates(char* s) {
int len = strlen(s);
int index = 1;
char *res = malloc(sizeof(char)*(len+1));
res[0] = s[0];
for(int i = 1; i < len; i++){
if(index == 0 || s[i] != res[index - 1]){
res[index] = s[i];
index++;
}
else{
index--;
}
}
res[index] = '\0';
return res;
}