字符串相关题

1.字符串空格替换

题目
传入的是字符输出的长度;
—>字符指针的使用: char* str; strcpy(str,s.c_str());
—>赋值法:先统计空格数量,从后往前赋值替换;newlen=len+count*2; char ch[20]="";

2.字符串的全排序

题目
---->递归方法:定义void Permutation(vector &result,string str,int start,int end);如果start==end时,str保存(递归调用void函数也要返回,return);for循环(int i=start;主要完成每次将一个字符放到字符串首部)里面if(为了排除重复字符的排序i!=start && str[i]==str[start])continue; 交换start与i在字符串中的位置,递归str后面的;
Permution(res,str,0,str.size());

注意函数里面的是string str,而不是string &str;为了不让其再递归中改变str的值;

3.最长公共连续子序列LCS:

注意与最长公共子串不同;if(str1[i-1]==str2[j-1]) dp[i][j]=dp[i-1][j-1]=1;result=max({result,max});else dp[i][j]=0;
打印只需判断result值师傅发生改变,并使用end保持i的位置即可;

—>动态规划:使用一个二维数组保存每一个的状态值;dp[i][j]={dp[i][j]+1,s[i-1]=t[j-1]时},else if(dp[i-1][j]>dp[i][j-1]) dp[i][j]=dp[i-1][j] else{}};
c(len1+1,vector(len2+1));
—>如果要打印其值:在三个判断后面加入标志;vec[i][j]分别为1,2,3;在int i=s.size(),j=t.size();

打印子序列的值

4.求一个字符串最长回文子串:

题目

—>动态规划解决:dp[i][j]表示字符串第i个字符到第j个字符组成的字符串为回文;

注意对l、i、j的使用顺序;

如果i+1到j-1为回文,那么如果s[i]==s[j]时,i到j就是回文;
分别以1个字符扩散时,以两个字符扩散时,其他情况;
如果dp[i][j]为真同时l+1>ans时截取;

class Solution {
public:
    string longestPalindrome(string s) {
        int n = s.size();
        vector<vector<int>> dp(n, vector<int>(n));
        string ans;
        for (int l = 0; l < n; ++l) { //对字符串中回文长度为l进行判断;
            for (int i = 0; i + l < n; ++i) {
                int j = i + l;
                if (l == 0) {  //表示字符子串长度为1时;
                    dp[i][j] = 1;
                }
                else if (l == 1) { //字符子串长度为2时;即相邻的两个字符
                    dp[i][j] = (s[i] == s[j]);
                }
                else { //长度大于2时
                    dp[i][j] = (s[i] == s[j] && dp[i + 1][j - 1]);//判断当前i+1到j-1的子串是回文,并且i和j位置的相对;以l=2时,(s[0]==s[2] &&dp[1][1]) l=3时,(s[0]==s[3] && dp[1][2])
                }
                if (dp[i][j] && l + 1 > ans.size()) { //如果i到j为回文且l+1回文长度>size时;
                    ans = s.substr(i, l + 1);
                }
            }
        }
        return ans;
    }
};

–>中心扩散法:
定义一个 expendaroundcenter(string s,int left,int right) //为满足奇数和偶数扩展
分别获得以单个字符或者双个字符为扩展的字符长度-1;即j-i-1;
mlen更新为最大值,在计算start和end;

注意更新start=i-(mlen-1)/2;
end=i+mlen/2;

class Solution {
public:
    string longestPalindrome(string s) {
        int len=s.size();
        if(len==0||len==1)
            return s;
        int start=0;//记录回文子串起始位置
        int end=0;//记录回文子串终止位置
        int mlen=0;//记录最大回文子串的长度
        for(int i=0;i<len;i++)
        {
            int len1=expendaroundcenter(s,i,i);//一个元素为中心
            int len2=expendaroundcenter(s,i,i+1);//两个元素为中心
            mlen=max(max(len1,len2),mlen);
            if(mlen>end-start+1)
            {
                start=i-(mlen-1)/2;
                end=i+mlen/2;
            }
        }
        return s.substr(start,mlen);
        //该函数的意思是获取从start开始长度为mlen长度的字符串
    }
private:
    int expendaroundcenter(string s,int left,int right) //为满足奇数和偶数扩展;
    //计算以left和right为中心的回文串长度
    {
        int L=left;
        int R=right;
        while(L>=0 && R<s.length() && s[R]==s[L])
        {
            L--;
            R++;
        }
        return R-L-1;
    }
};

5.字符串中第一个只出现一次的字符(索引位置):

题目

6.左旋转字符串:

左旋
---->返回str.substr(n%len)+str.substr(0,n%len);

多熟悉其字符串的函数;

7.翻转单词顺序列:

—>a.使用stack保存单词,但是记得将最后一个单词入栈(在s.top()时,如果s为空,则会出现段错误); b.使用temp保存当前单词,使用res保存遍历的单词(res=" “+temp+res,temp=”");返回temp+res;

注意可能同样的题对于输出有着不一样的要求,如"student a am I."对leetcode输出为"I am a student.“而剑指office要求输出为"I. am a student”;明显前面难,具体问题具体分析;
leetcode测试例子情况更多点,覆盖面全;

8.扑克牌的顺序:

题目
---->先排序在计算,使用sum=n[i+1]-n[i]-1来统计需要多少个0;注意需要判断元素相同时;count-sum>=0返回true;

排序时:在判断时符号不要写反,同时不要少些:如if(a>b){} else if(a<b);这将导致a=b时无法进行;
调用C++的sort方法:
sort(vec.begin(),vec.begin()+num,compareMother);

9.字符串转换为整数

题目
—>注意判断不合法数据以及数据是否越界,先判断第一个字符;不能使用转换函数;
atoi有长度限制;

int i=atoi(s.c_str());c_str()将字符串函数转为char*形;atoi将其转为整形;

剑指office测试用例有bug;

10.正则表达式匹配(.*):

题目
—>1.先对传入的两个指针看是否为空,在判断其指针值是否都为’\0’,在判断*str!=’\0’时,*p==’\0’;

2.先判断*(p+1)==*时;
3.最后判断当前字符相等时;有两种相等条件;
4.最后输出false;

因为是字符串,判断是否结束为是否等于’\0’;

11.表示字符串(e)的数字:

题目

注意:科学计数法:e或E后面为(+ -)?;后面必须为整数;且e前面必须有数字;

----->按字符串顺序分类讨论:
1.先对输入的char*进行合法性判断;
2.处理第一个字符;
3.定义三个变量num,dot,nume分别记录数字个数、点个数、e或E个数;
4.分别判断是否为数字、点、E或e;
5.当为.时,判断是否合法 即dot>0 || nume>0; 排除这种可能12e+4.3;因为nume>0成立表示dot<=0;
6.当为E或e时,判断nume>0 || num==0;排除-e123; 再取出后面的+或-;再判断-+后的字符是否为’\0’;排除123e;

12.字符流中的第一个重复的(无#):

题目
----->哈希的思想,vector vec(256,0);vec[str[i]]++; 在遍历看其索引位置是否为1;

//数组初始化
int ch[256]={0};
array<int,256> ch={0};
vector<int> hash(256,0); //不能声明为类的全局变量
//类的成员变量声明
vector<int> val{vector<int>(256,0)} //C++11
//或者通过构造函数初始化;C++11以前
class test{
private:
	vector<int> arr;
	vector<double> arr2;
public:
	test():arr(5,0),arr2(256,0){};
}

历史性转折:后面的习题更多的将是leetcode的上面的题;

13.字符串Z型打印(leetcode):

题目
------>分类讨论,
当numRows<=1时,直接输出,
当num>1时,定义vector arr,分别向上和向下运动;使用父类;
flag标记向上或向下方向;row(上下移动)标记向那个vec中加入当前字符;

感觉本题难点在于想到合适的数据结构存放每一行的字符;
如本题是vector arr;如果打算用二维字符数组存放那么难点将大大增加;

猜你喜欢

转载自blog.csdn.net/qq_42698422/article/details/106723401