14. 最长公共前缀
char * longestCommonPrefix(char ** strs, int strsSize){//是公共前缀,意思是不去看中间的子串,我还在动态规划解决,傻傻傻
if(strsSize==0)
return "";
char *p=strs[0];//定义一个指针变量指向第一个字符串
int i,j;
for(i=1;i<strsSize;i++){
j=0;
while(p[j]!='\0'&&strs[i][j]!='\0'){
if(p[j]!=strs[i][j])
break;
j++;
}
p[j]='\0';
if(p==NULL)//是所有字符串的公共前缀,若任一两者出现不相等的情况,则返回空
return "";
}
return p;
}
3. 无重复字符的最长子串
与这题类似,我之前在哪遇到过一次,但是拿到题,还是想到的暴力法,多加总结呀。不过好在能非常快速看懂最优解
int lengthOfLongestSubstring(char * s){//思维是有的,但是想到的是暴力破解,并没有想到用下标记录数字上一次出现的位置来代表是否出现过
int i, j = 0, count = 0, max = 0, start = 0;
int *index=(int *)malloc(sizeof(int)*128);//ascall码,用一字节表示字符,最高位不用,所以最多128个字符。
memset(index,0,sizeof(int)*128);//index[s[i]]表示该字符还未出现过
for(i=0;s[i]!='\0';i++)
{
if(index[s[i]]>start)//若if成立,代表s[i]在0~(i-1 )之间至少出现过一次
{
count = i-start;
if(count>max)
{
max = count;
}
start = index[s[i]];//start移动到重复数字上一回出现位置的下一位
}
index[s[i]] = i+1;//记录s[i]出现的最新位置;这个+1很巧哦。虽然本意是为了和0区别,因为直0表示没有出现过嘛。但是很巧的是,避免了遇到重复数字时的挪动
}
count = i-start;
free(index);
return count>max?count:max;
}
242. 有效的字母异位词
题目意思是判断s和t是否是相同字母不同排序结果的字符串 因为这道题有small tip,限制了只是小写字母哟 第二版相对于第一版来说,就是空间复杂度少了一些,区别在while代码块哪。第一版分别对字符串s和t各个字母出现的次数进行加和;第 二版则是字符串s在对应的位置+,字符串t在对应的位置-。
由于本题的字符串只包含 26 个小写字符,因此可以使用长度为 26 的整型数组,来映射字符与出现次数,然后比较两个字符串出现的字符数量是否相同
第一版
bool isAnagram(char * s, char * t){
int length1=strlen(s),length2=strlen(t),i;
int *count1=(int *)malloc(sizeof(int)*26);
memset(count1,0,sizeof(int)*26);
int *count2=(int *)malloc(sizeof(int)*26);
memset(count2,0,sizeof(int)*26);
bool temp=true;
if(length1!=length2)
return false;
while(i<length1){
count1[s[i]-'a']++;
count2[t[i]-'a']++;
i++;
}
for(i=0;i<26;i++){
if(count1[i]!=count2[i]){
temp=false;
break;
}
}
free(count1);
free(count2);
return temp;
}
第二版
bool isAnagram(char * s, char * t){
int length1=strlen(s),length2=strlen(t),i;
int *count1=(int *)malloc(sizeof(int)*26);
memset(count1,0,sizeof(int)*26);
bool temp=true;
if(length1!=length2)
return false;
while(i<length1){
count1[s[i]-'a']++;//区别在此
count1[t[i]-'a']--;
i++;
}
for(i=0;i<26;i++){
if(count1[i]!=0){//区别在此
temp=false;
break;
}
}
free(count1);
return temp;
}
796. 旋转字符串
哇,这道题说难也不难,我写了三个版本,顺序为倒序,依次排放在下面了,每个说明的序号和代码的序号都一一对应。
- 第三版时间复杂度O(n),空间复杂度O(n)。最坑的是strncpy最后不会自动填充’\0’!!!然后我查了半天才找到为什么越界的原因,emmmm。不过喃strcpy就会自动填充哦。
- 第二个空间复杂度O(1),思维可以用线性代数矩阵的逆来理解,是一个意思。其实第二版很有意思的,这算法是我在算法视频上看到的,my dream universty had tested it at 2019.
- 我不想说我最开始写的那个版本,完全和旋转的概念没有搭上边,只解了字符串中没有重复字母的情况,通过31/49的用例。
bool rotateString(char * A, char * B){
1.
int length=strlen(A),i,length1=strlen(B);
if(!length&&!length1)
return true;
char *result=(char *)malloc(sizeof(char)*(length+1));
for(i=0;i<length;i++){
strncpy(result,A+i,length-i);
strncpy(result+length-i,A,i);
result[length]='\0';
if(!strcmp(result,B)){
return true;
}
}
return false;
}
2.
void ReverseString(char *s,int from,int to){
char t;
while(from<to){
t=s[from];
s[from]=s[to];
s[to]=t;
from++;
to--;
}
}
void leftRotateString(char*s,int n,int m){//可以用线性代数,矩阵的逆来理解。字符串的长度为n,旋转m次
ReverseString(s,0,m-1);
ReverseString(s,m,n-1);
ReverseString(s,0,n-1);
}
bool rotateString(char str[], char * B){//说明一下这个地方,之前我用的指针接收字符串A,但是旋转一次之后字符串就被改了,我第二次旋转还需要用原来的字符串。
int i,length=strlen(str),length1=strlen(B);
if(length==0&&length1==0)
return true;
char temp[length+1];
strcpy(temp,str);//这个就用一个数组接收
for(i=1;i<=length;i++){
//char* p=A;
strcpy(str,temp);//每一次循环,都把我保存的字符串副本给str
leftRotateString(str,length,i);
if(!strcmp(str,B))
return true;
}
return false;
}
3.
/*int left,right,i,length=strlen(B),decimal1,decimal2=(int)A[0],length1=strlen(A);只解了字符串中没有重复字母的情况,通过31/49的用例
if(length!=length1)
return false;
char *left1=(char *)malloc(sizeof(char)*(length+1));
char *left2=(char *)malloc(sizeof(char)*(length+1));
char *right1=(char *)malloc(sizeof(char)*(length+1));
char *right2=(char *)malloc(sizeof(char)*(length+1));
bool flag=false;
for(i=0;i<length;i++){
decimal1=(int)B[i];//c语言单个字符不能进行比较,必须转换为ASCALL码
if(decimal1==decimal2){
left=i;
break;
}
}
right=length-left;
strncpy(left1,A,right);
strncpy(right1,A+right,left);
strncpy(left2,B,left);
strncpy(right2,B+left,right);//给字符串赋值之后要加结束符号‘\0’,不然越界
left1[right]='\0';
left2[left]='\0';
right1[left]='\0';
right2[right]='\0';
if(!strcmp(left1,right2)&&!strcmp(left2,right1))
flag=true;
free(left1);
free(left2);
free(right1);
free(right2);
return flag;*/
1332. 删除回文子序列
这道题真是绝了,读题很重要呀!!! 然后本题考的是子序列,emmmmm
注释掉的部分是我按照子串的思路写的,通过测试用例大概31/49,在字符串“baabb”的时候,如果按照回文子串来讲,应该删除3次,但是我的是一次,方法有问题。
总之,在看完别人说的坑之后,觉得自己费的时间太可惜了。
int removePalindromeSub(char * s){//空字符串0次;整体回文1次;第三种则是一次子序列a,一次子序列b,所以最多2次
int length=strlen(s);
int i=0,j=length-1;
if(length==0)
return 0;
while(i<j){
if(s[i++]!=s[j--])
return 2;
}
return 1;
/*int i,j,length=strlen(s),m,sum=0;
bool flag;
for(i=0;i<=length/2;i++){
m=i;
flag=true;
for(j=length-1;j>i;j--){
if(s[m]!=s[j])
flag=false;
break;
m++;
}
if(flag){
sum=length+i-j;
break;
}
}
if(s==NULL){
return 0;
}else{
return sum;
}*/
}
1108. IP 地址无效化
用到一个库函数memcpy()
char * defangIPaddr(char * address){
int length=strlen(address),count=0,sum=length+7,i;
char *returnArray=(char *)malloc(sizeof(char)*(sum));//7为三对[]和一个结束符号
memset(returnArray,'0',sizeof(char)*(sum));
returnArray[length+6]='\0';
for(i=0;i<length;i++){
if((*address)!='.'){
*returnArray++=*address++;
}else{
memcpy(returnArray,"[.]",3);
returnArray+=3;
address++;
}
}
return returnArray-length-6;//最后returnArray挪到队尾了,需要前移
}
409. 最长回文串
被注释掉的部分的错误原因是,我没有成双成对的思想。想的是把最大的奇数找到,然后利用它。结果没想到如果最大的奇数是5,那我奇数3对应的字符其中的两也可以做回文字符阿。蠢的不行了。
诺,下图为被注释掉的代码的运行结果。
int length=strlen(s),i,max=0,sum=0;
int *count1=(int *)malloc(sizeof(int)*52);
memset(count1,0,sizeof(int)*52);
for(i=0;i<length;i++){
if((s[i]-'A')>=0&&(s[i]-'A')<=25)
count1[s[i]-'A']++;
else
count1[s[i]-'A'-6]++;
}
for(i=0;i<52;i++){
sum+=count1[i]/2*2;//这样就可以成双成对了,不用再去寻找最大的奇数是多少
}
if(sum<length)//说明至少有一个为单个的,无法和别人配对
sum++;
free(count1);
return sum;
205. 同构字符串
*解题思路
最开始看到这题,我想的是,先用两数组把两字符串里各字符出现的次数记录下来,然后按从大到小的顺序排,然后再比较是否相等。理论上这方法是可行的,不过我没去试。
然后换了大神的思维,这个方法我用笔画了画才懂的,有点晦涩。记录一个字符上次出现的位置,如果两个字符串中的字符上次出现的位置一样,那么就属于同构。
bool isIsomorphic(char * s, char * t){//开辟两个256的整型数组,计算每个字母出现的位置
int *preindex1=(int *)malloc(sizeof(int)*256);
int *preindex2=(int *)malloc(sizeof(int)*256);
memset(preindex1,0,sizeof(int)*256);//0代表从未出现过
memset(preindex2,0,sizeof(int)*256);
int i,length=strlen(s);
for(i=0;i<length;i++){
if(preindex1[s[i]]!=preindex2[t[i]])
return false;
preindex1[s[i]]=i+1;//最新的s[i]出现在哪个位置
preindex2[t[i]]=i+1;
}
free(preindex1);
free(preindex2);
return true;
}
1170. 比较字符串最小字母出现频次
这道题没啥说的,对于我自己而言加深了对二级指针和二维数组的异同的理解
char ** queries,queries[i]代表代表第i+1行数据
int f(char *p){//思考着思考着,就忘记了还有f函数判断最小字符这要求
int i,min,length=strlen(p),count=0;
min=p[0];
for(i=1;i<length;i++){
if(p[i]<min)
min=p[i];
}
for(i=0;i<length;i++){
if(p[i]==min)
count++;
}
return count;
}
int* numSmallerByFrequency(char ** queries, int queriesSize, char ** words, int wordsSize, int* returnSize){
int *count1=(int *)malloc(sizeof(int)*queriesSize);
int *count2=(int *)malloc(sizeof(int)*wordsSize);
int *result=(int *)malloc(sizeof(int)*queriesSize);
memset(result,0,sizeof(int)*queriesSize);
int i,j,k,length;
for(i=0;i<queriesSize;i++){
count1[i]=f(queries[i]);
}
for(j=0;j<wordsSize;j++){
count2[j]=f(words[j]);
}
for(i=0;i<queriesSize;i++){
j=0;
while(j<wordsSize){
if(count1[i]<count2[j])
result[i]++;
j++;
}
}
free(count1);
free(count2);
(*returnSize)=queriesSize;
return result;
}
67. 二进制求和
第二遍看自己写的,觉得真的……,zz
首先我是考虑到了,两个加数的位数不同,但第一想法是判断哪个字符数组先遍历完。不过,碰到一个问题,假设数组a先遍历完,我第一次是直接把未遍历完的数组b直接赋值给结果数组C的,忽略了a[0]+b[j]的和也有进位的可能。
So, i change my thought. 不足位的补0。i>-1?a[i]-‘0’:0)+(j>-1?b[j]-‘0’:0,这一句就是实现我的思想的
char * addBinary(char * a, char * b){
int length1=strlen(a),length2=strlen(b),length;//length1的长度未包含'\0'
length=length1>length2?(length1+1):(length2+1);//加一,以防最高位进位
char *c=(char *)malloc(sizeof(char)*(length+1));
memset(c,'0',sizeof(char)*(length+1));//再+1,最后一位为结束符
c[length]='\0';//字符数组的最后一位下标为length
int *carry=(int *)malloc(sizeof(int)*(length+1));//用于存放进位位的
memset(carry,0,sizeof(int)*(length+1));
int i,j,k,sum;
char temp;
for(i=length1-1,j=length2-1,k=0;((i>=0)||(j>=0)||carry[k])&&k>-1;i--,j--,k++){//char数组的最后一位为\0
sum=(i>-1?a[i]-'0':0)+(j>-1?b[j]-'0':0);//两个二进制数,位数不同,用0补齐
if((sum+carry[k])>1){
c[k]=(sum+carry[k])-2+'0';
carry[k+1]=1;
}else{
c[k]=sum+carry[k]+'0';
}
}
for(i=0,j=length-1;i<j;i++,j--){//由于上一个for中,我的k老是有问题,越界,不得不把结果逆序存放,然后再倒序一下,有点费时间
temp=c[i];
c[i]=c[j];
c[j]=temp;
}
if(c[0]=='0'){//也即最高位没有进位
for(i=0;i<length;i++){
c[i]=c[i+1];
}
}
free(carry);
return c;
}
696. 计数二进制子串
- 循环生成偶数位的字符串。然后再用变量i,j前后遍历。i与j不同的次数只能为一次,如果是两次及以上则不符合拉。以01或者10为中间分界,左边i,j指向的数相同的次数需要和右边i,j指向的数相同的次数
相同。aaaaa,没有实现出来。
以下就是大佬的代码了哟,总体思路和我很像阿,我们计数的方式不一样,这就是区别吧。
好好记得这个思路过程。
用静态图表述一下思维,等我会画动图了,我再更新
int countBinarySubstrings(char * s){//有想过最i,j以前以后走,也知道要记录01or10的变化,但在通知数量,记录值方面还是没有想的那么好
int i,pre=0,cur=1,count=0;
for(i=0;i<strlen(s)-1;i++){
if(s[i]==s[i+1])
cur++;
else{
pre=cur;
cur=1;
}
if(pre>=cur)
count++;
}
return count;
}
- 最后一个单词的长度
int lengthOfLastWord(char * s){
int i=0,j=0,length=0;
while(s[j]){
if(s[j]==' '&&s[j+1]&&s[j+1]!=' ')//记得处理最后1bit为空的情况,还有空格连续的情况
i=j+1;
j++;
}
while(s[i]&&s[i]!=' '){
i++;
length++;
}
return length;
}