Leecode初级算法C++题解(字符串篇)

5 篇文章 1 订阅
1 篇文章 0 订阅

字符串篇

力扣初级算法链接

1.反转字符串(leecode第344题)

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 char[] 的形式给出。不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
你可以假设数组中的所有字符都是 ASCII 码表中的可打印字符。

1.1 双指针法

算法:就是将头尾的元素互换,双指针,start和end一个向前一个向后。

class Solution {
public:
    void reverseString(vector<char>& s) {
        int start=0;
        int end=s.size()-1;
        while(start<end)
        {
            swap(s[start],s[end]);
            start++;
            end--;
        }       
    }
};
1.2 reverse法

算法:c++自带reverse反转函数,string.begin()和end()返回的都是迭代器iterator位置。

class Solution {
public:
    void reverseString(vector<char>& s) {
       reverse(s.begin(),s.end());
    }    
};
1.3递归法

算法:其实和第一个方法相似,只不过用递归来实现。

class Solution {
public:
    void reverseString(vector<char>& s) {
       fun(0,s.size()-1,s);
    }  
    void fun(int start,int end, vector<char>& s)
    {
        if(start>end)
            return;
        char temp=s[start];
        s[start]=s[end];
        s[end]=temp;
        fun(start+1,end-1,s);
    }
};

2.整数反转(leecode第7题)

题目:给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。

示例 1:				示例 2:				示例 3:
输入: 123			输入: -123			输入: 120
输出: 321			输出: -321			输出: 21

注意:
假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。

2.1整除法

算法:通过将数字通过对10取余,整数除法拆分数字,后再反向组合。

class Solution {
public:
    int reverse(int x) {
        int symbol=0,temp;
        long res=0,x_l=x;
        if(x_l<0)		//保存符号
        {
            symbol=1;
            x_l=-x_l;		//	这里必须将x从int转换成long型,不然会出错
        }        
        while(x_l/10>0)
        {
            temp=x_l%10;
            res=res*10+temp;
            x_l/=10;
        }
        res=res*10+x_l;
        if(symbol==1)
            res=-res;
        if(res>(pow(2,31)-1) || res<-pow(2,31)+1)
            return 0;
        else
            return res;
    }
};

看了官方解题,其实解题思路和我一致,但是很多地方做的比我好,例如int型变量的范围不用自己算,可以用INT_MAX,INT_MIN表示;还有我是处理不好负数整除,所以把符号提出来,官方则没有,附上c++整数除法取模知识的参考链接;我是把数放在long型变量里处理防止溢出,官方则直接判断。

补充个小知识:
int整数 		取余是向零取整的
		取模: 余数=被除数-商×除数 (*)
7/(-4)=-1;	-7/4=-1;
7%(-4)=3;	-7%4=-3;	
对于有符号整数与无符号整数间的除法,C/C++会将有符号整数转换为无符号整数,
需要特别注意的是,符号位并没有丢失,而是变成了数据位参与运算。这就是
(-7)/(unsigned)4不等于-1,而等于1073741822的原因。	

附上官方解题

class Solution {
public:
    int reverse(int x) {
        int rev = 0;
        while (x != 0) {
            int pop = x % 10;
            x /= 10;
            if (rev > INT_MAX/10 || (rev == INT_MAX / 10 && pop > 7)) return 0;
            if (rev < INT_MIN/10 || (rev == INT_MIN / 10 && pop < -8)) return 0;
            rev = rev * 10 + pop;
        }
        return rev;
    }
};

下面这个是结合起来运行最快的方法,运行0ms,本来是用x_l=labs(x),但是很花时间。labs()函数是对long型取绝对值,输出也是long型变量。

class Solution {
public:
    int reverse(int x) {
        int sign=x<0? -1:1;
        long res=0,x_l=x;
        if(x<0)
            x_l=-x_l;	//这里如果是x_l=-x,-INT_MAX还是溢出的
        while(x_l)
        {
            res=res*10+x_l%10;
            x_l/=10;
        }
        res=sign*res;
        if(res>INT_MAX || res<INT_MIN)
            return 0;
        return res;
    }
};
2.2字符法

算法:将数字转换为字符处理,通过sprintf函数将数字转为字符,这里sprintf的用法得注意。注意几点:

C 库函数 int sprintf(char *str, const char *format, ...) 发送格式化输出到 str 所指向的字符串。
1、如果数字-123通过sprintf转为字符,字符串s[0]='-'
2、sprintf转为字符后,多余的位置值会改变
3、sprintf函数返回值是写入了多少位字符,后面没写入会追加空字符
4、这题x输入最大的字符数应该是11位,但是我给s[11]空间是有问题的,s[12]就可以,不
   知道为啥,待解
class Solution {
public:
    int reverse(int x) {
        char s[12]={'0'};
        long res=0;
        int n=sprintf(s,"%d",x);
        for(int i=n;i<11;i++)
            s[i]='0';
        if(x<0)
        {
            for(int i=10;i>0;i--)
                res=res*10+s[i]-'0';
            res=-res;
        }
        else
            for(int i=10;i>=0;i--)
                res=res*10+s[i]-'0';
            
        if(res>INT_MAX || res<INT_MIN)
            return 0;
        return res;
    }
};

3.字符串中的第一个唯一字符(leecode第387题)

题目:给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。

案例:		
s = "leetcode"			s = "loveleetcode",
返回 0.				返回 2.

注意事项:您可以假定该字符串只包含小写字母。

3.1 哈希法

算法:通过map建立哈希表,存入字符个数,然后输出第一个个数唯一的字符下标。这里想说一下,如下程序建立的map没有初始化,第二个量为什么默认初始化为零。

class Solution {
public:
    int firstUniqChar(string s) {
        map<char,int> table;
        int n=s.size();
        for(int i=0;i<n;i++)
            table[s[i]]++;
        for(int i=0;i<n;i++)
            if(table[s[i]]==1)
                return i;
        return -1;        
    }
};

4. 有效的字母异位词(leecode第242题)

给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的一个字母异位词。

示例 1:
输入: s = "anagram", t = "nagaram"
输出: true
示例 2:
输入: s = "rat", t = "car"
输出: false

说明:
你可以假设字符串只包含小写字母。
进阶:
如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?

4.1 map哈希法

算法:通过map建立t和s的哈希表,通过查找个数是否一致判断结果

class Solution {
public:
    bool isAnagram(string s, string t) {
        map<char,int> s_table,t_table;
        for(int i=0;i<s.size();i++)
            s_table[s[i]]++;
        for(int i=0;i<t.size();i++)
            t_table[t[i]]++;
        for(int i=0;i<t.size()|| i<s.size();i++)
            if(t_table[t[i]]!=s_table[t[i]] ||t_table[s[i]]!=s_table[s[i]])
                return false;            
        return true;                    
    }
};
4.2 数组哈希法

算法:通过数组建立哈希表,参考别人的答案,该方法速度比较快

class Solution {
public:
    bool isAnagram(string s, string t) {
        int a[26]={0},b[26]={0};
        int i;
        
        for(i=0;s[i]!='\0';i++)	//建立哈希表s
            a[s[i]-'a']++;
        for(i=0;t[i]!='\0';i++)	
            b[t[i]-'a']++;
                   
        for(i=0;i<26;i++)
            if(a[i]!=b[i])
                return false;
        return true;
    }
};
4.3 排序法

算法:排序后比较,该题就是判断两个字符串是否相同

class Solution {
public:
    bool isAnagram(string s, string t) {
        int i;
        sort(s.begin(),s.end());
        sort(t.begin(),t.end());
        for(i=0;s[i]!='\0' && t[i]!='\0';i++)
            if(s[i]!=t[i])
                return false;
        if(s[i]!='\0' || t[i]!='\0')
            return false;
        return true;
    }
};

5.验证回文字符串(leecode第125题)

5.1双指针法

算法:题目比较简单,只要把大小写处理下还有非字母和数字的字符排除,然后首尾比较就好了,唉,但是我在做的时候因为把判断大小写时的=给忘了,折磨我好久。不要忘了等于,不要忘了等于,不要忘了等于!重要的事情说三遍!

class Solution {
public:
    bool isPalindrome(string s) {
        if(s.size()==0)
            return true;
        int start=0;
        int end=s.size()-1;
        while(start<end)
        {
            if(s[start]<='Z' && s[start]>='A')
                s[start]+='a'-'A';
            if(s[end]<='Z' && s[end]>='A')
                s[end]+='a'-'A';
            if( !((s[start]>='a' && s[start]<='z') || (s[start]>='0' &&s[start]<='9')) )
            {
                start++;
                continue;
            }
            if( !((s[end]>='a' && s[end]<='z') || (s[end]>='0' &&s[end]<='9')) )
            {
                end--;
                continue;
            }
            if(s[start]==s[end])
            {
                start++;
                end--;
            }
            else
                return false;
        }
        return true;       
    }
};

6.字符串转换整数(leecode第8题)

感觉这题好蠢啊,没什么营养,一直是不同测试案例调,也可能是我思路错了,不想弄了,下面是调一半的程序,这个程序是对+,-,空格,数字都设置了标志位,分别考虑,且参考plc的方法考虑互锁。
已经调好了,下面的是可以运行了,设置了一个accept接受标志。

class Solution {
public:
   int myAtoi(string str) {
       long res=0;
       int sign=1;
       int accept=0;
       if(str.size()==0)
           return 0;    
       for(int i=0;i<str.size();i++)
       {
           if(str[i]=='-')
           {
               if(accept==1)
                   return res*sign;
               sign=-1;
               accept=1; 
            }
             else if(str[i]=='+')
           {
               if(accept==1)
                   return res*sign;
               sign=1;
               accept=1;
           }
           else if(str[i]==' ')
           {
               if(accept==0)
                   continue;
               if(accept==1)
                   return res*sign;
           }
            else if(str[i]>='0' && str[i]<='9')
           {
               accept=1;
               if(sign==1 && (res>INT_MAX/10 || (res==INT_MAX/10 && str[i]-'0'>7)) )
                   return INT_MAX;
               if(sign==-1 && (res>INT_MAX/10 || (res==INT_MAX/10 && str[i]-'0'>8)) )
                   return INT_MIN;
               res=res*10+str[i]-'0';                
           }
           else 
               return res*sign;
       }
       return res*sign;
   }
}

7.实现strstr()

题目:实现 strStr() 函数。
给定一个 haystack 字符串和一个 needle 字符串,在 haystack 字符串中找出 needle 字符串出现的第一个位置 (从0开始)。如果不存在,则返回 -1。
示例 1:
输入: haystack = “hello”, needle = “ll”
输出: 2
示例 2:
输入: haystack = “aaaaa”, needle = “bba”
输出: -1
说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。

7.1暴力法

直接遍历所有情况,但是超时。

class Solution {
public:
    int strStr(string haystack, string needle) {
        int h=haystack.size();
        int n=needle.size();
        int temp;
        if(n==0)
            return 0;
        for(int i=0;i<h;)
        {
            temp=i;
            for(int j=0;j<n;)
            {
                if(haystack[i]==needle[j])
                {
                    i++;
                    j++;
                }
                else
                    break;
                if(j==n)
                    return temp;
            }
            i=temp+1;
        }
        return -1;
    }
};
7.2 内置函数法
class Solution {
public:
    int strStr(string haystack, string needle) {
        if(needle.empty()) return 0;
        int pos=haystack.find(needle);//在字符串haystack中查找needle        
        return pos;	//未找到find()返回-1
    }
};
7.3KMP方法

唉写不动了,这个我之前写过,参考我这篇博客吧。
用c++具体实现的KMP模式匹配算法

class Solution {
public:
    int strStr(string haystack, string needle) {
        return KMP(haystack,needle);       
    }
    void get_next(string &T,vector<int> &next)
    {
        int i,j;
        i=0;
        j=-1;
        next.push_back(-1);
        int tmp=T.size();
        while(i<tmp)
        {
            if(j==-1 || T[i]==T[j])
            {
                ++j;
                i++;
                next.push_back(j);
            }
            else
                j=next[j];
        }       
    }
    int KMP(string &x,string &T)
    {
        vector<int> next;
        int i=0,j=0;
        
        get_next(T,next);
        
        int tmp2=x.size();
        int tmp1=T.size();
        while(i<tmp2 && j<tmp1)   
        {
            if(j==-1 || x[i]==T[j] )	//这里的两个条件不能互换,一换就错了
            {				//这里折磨了我半天,难受
                i++;
                j++;
            }
            else
                j=next[j];
        }
        if(j==tmp1)
            return i-j;
        else 
            return -1;
    }    
};

8. 报数(leecode第38题)

报数序列是一个整数序列,按照其中的整数的顺序进行报数,得到下一个数。其前五项如下:

  1. 1
  2. 11
  3. 21
  4. 1211
  5. 111221

1 被读作 “one 1” (“一个一”) , 即 11。
11 被读作 “two 1s” (“两个一”), 即 21。
21 被读作 “one 2”, “one 1” (“一个二” , “一个一”) , 即 1211。
给定一个正整数 n(1 ≤ n ≤ 30),输出报数序列的第 n 项。
注意:整数顺序将表示为一个字符串。

示例 1:			示例 2:
输入: 1			输入: 4
输出: "1"		输出: "1211"
8.1递归法

算法:递归法,给定一个初始项,通过递归得到一个第n-1项,再用这个第n-1项算出第n项return 结果

class Solution {
public:
    string countAndSay(int n) {
        if(n==1)
            return "1";
        string res=countAndSay(n-1);
        string result;
        char count='1';
        char temp=res[0];
        int j=0;
        
        for(int i=1;i<res.size();i++)
        {
            if(temp==res[i])
                count++;  
            else
            {
                result.push_back(count);
                result.push_back(temp);
                temp=res[i];
                count='1';
            }                
        }
        result.push_back(count);
        result.push_back(temp);
        return result;
    }
};

下面这个程序原理和上面一样,不过在处理保存字符有点不同,注意到to_string是将数字转换成字符串,这里可以学习一下c++ string用+的连接,刚开始我用string+=char+char这种格式,是不对的。
对于string类型变量,我们可以直接用“+”或者“+=”进行字符串的连接,操作符非常方便。
用“+”风格字符串进行字符串连接时,操作符左右两边既可以都是string字符串,也可以是一个string字符串和一个C风格的字符串,还可以是一个string字符串和一个char字符。
而用“+=”风格字符串进行字符串连接时,操作符右边既可以是一个string字符串,也可以是一个C风格字符串或一个char字符。
string+=char可以,但是string+=char+char是不对的,改成string=string+char+char可以,所以=右边必须有一个string或者只能有一个char。

class Solution {
public:
    string countAndSay(int n) {
        if(n==1)
            return "1";
        string res=countAndSay(n-1);
        string result;
        int count=1;
        char temp=res[0];
        int j=0;
        
        for(int i=1;i<res.size();i++)
        {
            if(temp==res[i])
                count++;  
            else
            {
                result=result+to_string(count)+temp;
                temp=res[i];
                count=1;
            }                
        }
        result+=to_string(count);
        result+=temp;
        return result;
    }
};

9. 最长公共前缀(leecode第14题)

编写一个函数来查找字符串数组中的最长公共前缀。

如果不存在公共前缀,返回空字符串 “”。
示例 1:
输入: [“flower”,“flow”,“flight”]
输出: “fl”
示例 2:
输入: [“dog”,“racecar”,“car”]
输出: “”
解释: 输入不存在公共前缀。

说明: 所有输入只包含小写字母 a-z 。

9.1水平扫描法

算法:将第一个字符串作为参考,将strs后面的每个字符串依次和他比较,算出公共前缀。

(1)string& erase ( size_t pos = 0, size_t n = npos );//默认参数是0到结尾
(2)iterator erase ( iterator position );
(3)iterator erase ( iterator first, iterator last );
class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if(strs.empty()) return ""; //如果容器vector为空,则返回“”
        string res=strs[0];
        for(int i=1;i<strs.size();i++)
            for(int j=0;j<res.size();j++)
                if(res[j]==strs[i][j])
                    continue;
                else
                {
                    res.erase(j);
                    break;
                }            
        return res;
    }
};
9.2 水平扫描法

算法:上面是将两个字符串两个字符串的比较,下面是从每个字符串的首字符开始比较,得出结果

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if(strs.empty()) return ""; 
        string res;
        for(int i=0;i<strs[0].size();i++)
        {
            char t=strs[0][i];
            for(int j=1;j<strs.size();j++)
            {
                if(strs[j][i]!=t|| i == strs[j].size())
                    return res;                
            }
            res.push_back(strs[0][i]);
        }                
        return res;
    }
};
9.3 分治法

算法:该方法就是将第一种方法进行递归运算,和分治排序法的思想相似。

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if(strs.empty())
            return "";
        return marge(strs,0,strs.size()-1);
    }
    string marge(vector<string>& strs,int l,int r)
    {
        if(l==r)
            return strs[r];
        int mid=(l+r)/2;
        string lstr=marge(strs,l,mid);
        string rstr=marge(strs,mid+1,r);
        string res=commonPrefix(lstr,rstr);
        return res;
    }
    string commonPrefix(string lstr,string rstr)
    {
        string res;       
        for(int i=0;i<lstr.size() && i<rstr.size();i++)
        {
            if(lstr[i]!=rstr[i])
                return res;
            res.push_back(lstr[i]);       
        }
        return res;
    }
};

这里复习一下归并排序的方法

 void marge_sort(vector<int>& num,int l,int r)
    {
    	if(l==r)
    		return ;
        int mid=(l+r)/2;
        vector<int> lnum,rnum;
        marge_sort(num,l,mid);
        marge_sort(num,mid+1,r);
        
        for(int i=0;i<=mid-l;i++)	//对两部分已经排好序的数组进行合并
            lnum[i]=num[i+l];
        for(int i=0;i<=r-mid;i++)
            rnum[i]=num[mid+i];
        int j=0,k=0;
        for(int i=l;i<=r;i++)
        {
            if(lnum[j]<=rnum[k])
            {
                num[i]=lnum[j];
                j++;
            }
            else(lnum[j]>rnum[k])
            {
                num[i]=rnum[k];
                k++;
            }
        }

字符串篇也结束,还会持续更新。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值