1.字符串压缩
class Solution {
public:
string compressString(string S) {
if(S.length()==0) return S;
string compressResult;
int count=0;
int i=0;
int j=0;
while(i<S.length()&&j<S.length()){
if(S[i]==S[j]){
j++;
count++;
}
else{
compressResult+=S[i];
std::string countnums=std::to_string(count);
count=0;
compressResult+=countnums;
i=j;
}
}
compressResult+=S[i];
std::string countnums=std::to_string(count);
compressResult+=countnums;
if(compressResult.length()<S.length()) return compressResult;
else return S;
}
};
官方题解中的解法:
class Solution {
public:
string compressString(string S) {
if ((int)S.length() == 0) return S; // 空串处理
string ans = "";
int cnt = 1;
char ch = S[0];
for (int i = 1; i < (int)S.length(); ++i){
if (ch == S[i]) cnt++;
else{
ans += ch + to_string(cnt); // 注意 cnt 要转为字符串
ch = S[i];
cnt = 1;
}
}
ans += ch + to_string(cnt);
return ans.length() >= S.length() ? S : ans;
}
};
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/compress-string-lcci/solution/zi-fu-chuan-ya-suo-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
2.最长不含重复字符的子字符串
力扣上的测试用例跟剑指上的不同,没有假设字符串中只包含‘a’到z的字符,会出现“ ”这样的测试用例,用动态规划dp数组的这种解法,执行效率不好。
求最大元素的方法:auto biggest=std::max_element(dp.begin(),dp.end()),返回的是一个迭代器。
std::distance(std::begin(v), smallest) 这样就把下标位置求出来了
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.empty()) return 0;
int n=s.size();
if(n<=1) return n;
//我们创建一个长度为256的数组position用来存储每个字符上次出现在字符串中位置的下标
vector<int> position(256,-1);
vector<int> dp(n,0);
dp[0]=1;
int i;
position[s[0]]=0;
for(i=1;i<n;++i){
if(position[s[i]]==-1){
position[s[i]]=i;//注意对位置的更新
dp[i]=dp[i-1]+1;
}
else{
int d=i-position[s[i]];
position[s[i]]=i;
if(d<=dp[i-1]){
dp[i]=d;
}
else{
dp[i]=dp[i-1]+1;
}
}
cout<<dp[i]<<endl;
}
std::vector<int>::iterator biggest=std::max_element(std::begin(dp),std::end(dp));
return *biggest;
}
};
基于循环的代码:执行用时显著改善
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.empty()) return 0;
int n=s.size();
if(n<=1) return n;
//我们创建一个长度为256的数组position用来存储每个字符上次出现在字符串中位置的下标
vector<int> position(256,-1);
int maxLength=0;
int currentLength=0;
for(int i=0;i<n;++i){
int preindex=position[s[i]];
if(preindex<0||i-position[s[i]]>currentLength){
currentLength=currentLength+1;
if(currentLength>maxLength){
maxLength=currentLength;
}
}
else{
if(currentLength>maxLength){
maxLength=currentLength;
}
currentLength=i-position[s[i]];
}
position[s[i]]=i;
}
return maxLength;
}
};
如果想要用暴力法解决的话,需要先生成所有的子串再判断这个子串中有没有重复的字符。因为n是不确定的,没有办法用循环的办法来生成子串?在网上找到了用三层循环控制来生成子串的办法。需要用回溯法生成?
3.翻转字符串
题目一:剑指offer上的解法。第一步翻转句子中所有的字符。第二步再翻转每个单词中字符的顺序。我们可以通过扫描空格来确定每个单词的起始和终止位置。
void reverse(char *pBegin,char *pEnd);
char* reverseWords(char* s){
if(s==NULL) return NULL;
char* pBegin=s;
char* pEnd=s;
while(*pEnd!='\0'){//先确定pEnd的位置
pEnd++;
}
pEnd--;
reverse(pBegin,pEnd);//翻转整个句子
pBegin=s;
pEnd=s;
while(*pBegin!='\0'){
if(*pBegin==' '){//如果是空格就往前
pBegin++;
pEnd++;
}
else if(*pEnd==' '||*pEnd=='\0'){//
reverse(pBegin,--pEnd);//翻转这个单词
pBegin=++pEnd;//pBegin越过当前这个单词
}
else{
pEnd++;
}
}
return s;
}
void reverse(char *pBegin,char *pEnd){
if(pBegin==NULL||pEnd==NULL) return;
while(pBegin<pEnd){
char temp=*pBegin;
*pBegin=*pEnd;
*pEnd=temp;
pBegin++;
pEnd--;
}
}
力扣上比较麻烦的是要处理空格,两个单词之间可能有多个空格,句子前和后也可能有空格。
双指针从后往前遍历,一个指针找第一个不是空格的位置,第二个指针从刚刚找到的位置出发找第一个空格的位置,把这之间的单词顺序存放在结果数组里(缺点就是新开辟了一个空间存放结果)
作者:helloworld-o
链接:https://leetcode-cn.com/problems/fan-zhuan-dan-ci-shun-xu-lcof/solution/chun-c-shuang-zhi-zhen-bian-li-xiang-xi-zhu-shi-qi/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
C语言处理字符串要非常小心,在这里j是有可能等于-1的,
char* reverseWords(char* s){
int len=strlen(s);
if(len==0) return s;
int g=0;
int i=len-1;
int j=len-1;
while(s[g]==' '){
g++;
}
printf("%d\n",g);
if(g==len) return "";
int index=0;
char* res=(char *)malloc(sizeof(char)*(len+1));
while(i!=g-1){
while(i>=0 && s[i]==' ') i--;
//双指针从后往前遍历,一个 指针找第一个不是空格的位置,第二个指针从刚刚找到的位置出发找第一个空格的位置,把这之间的单词顺序存放在结果数组里(缺点就是新开辟了一个空间存放结果)
j=i;
while(j>=0 && s[j]!=' ') j--;
printf("j+1=%d,i=%d\n",j+1,i);
for(int k=j+1;k<=i;k++){//从j+1到i
res[index++]=s[k];
}
i=j;
res[index++]=' ';
}
//printf("%d\n",i);
//printf("%d\n",index);
res[index-1]='\0';//实际上是把最后的空格替换成结束符
return res;
}
题目二:左旋转字符串
字符串的左旋转操作,我们可以利用翻转字符串的函数。
char* LeftRotateString(char* pStr,int n){
if(pStr==NULL||n>strlen(pStr)) return NULL;
char* b1=pStr;
char* e1=pStr+n-1;
char* b2=pStr+n;
char* e2=pStr+strlen(pStr)-1;
reverse(b1,e1);
reverse(b2,e2);
reverse(b1,e2);
return pStr;
}
C++解法:substr的用法,第一个参数start是开始的索引,第二个是长度,如果如果没有写的话默认到最后一个字符。 如果不让用substr函数的话可以使用字符拼起来的方式
class Solution {
public:
string reverseLeftWords(string s, int n) {
if(s.size()==0) return "";
if(n>s.size()) return "";//不合法的输入
string s1=s.substr(0,n);
string s2=s.substr(n);
return s2+s1;
}
};
4.字符串转整数
这道题目在牛客网做过,但是牛客网的测试用例很简单。const int c1=42; const int *p2=&ci; //允许改变p2的值,这是一个底层const. int i=0; int *const p1=&i;//不能改变p1的值,这是一个顶层const
之前用到的一个程序:这个c=(int)(unsigned char)*nptr++,这个c是不是变成了这个字符的ASCII值了? NULL的ASCII值是0?
static uint64_t strTouint64(const char *nptr)
{
int c; /* 当前要转换的字符(一个一个字符转换成数字) */
uint64_t total; /* 当前转换结果 */
int sign; /* 标志转换结果是否带负号*/
/*跳过空格,空格不进行转换*/
while ( isspace((int)(unsigned char)*nptr) )
++nptr;
c = (int)(unsigned char)*nptr++;//获取一个字符准备转换
sign = c; /*保存符号标示*/
if (c == '-' || c == '+')
c = (int)(unsigned char)*nptr++; /*跳过'+'、'-'号,不进行转换*/
total = 0;//设置转换结果为0
while (isdigit(c)) {//如果字符是数字
total = 10 * total + (c - '0'); /* 根据ASCII码将字符转换为对应的数字,并且乘10累积到结果 */
c = (int)(unsigned char)*nptr++; /* 取下一个字符 */
}
//根据符号指示返回是否带负号的结果
if (sign == '-')
return -total;
else
return total;
}
可以观察一下这道题目的测试用例是怎么设计的:上面的程序是很值得参考的
没有通过的测试用例 2 000 000 000 000 000 000,该数用long long也已经不够了,所以必须要在while循环里进行判断。"-91283472332" 2147483648这个测试用例试了很久。
我想着应该有的测试用例:42 “ -42” 4193 with words, -2147483648, -2147483649, -2147483650,2147483647,2147483648,2147483649,-91283472332,2000000000000000000000. 0 "", + ,-,
class Solution {
public:
int strToInt(string str) {
//这里的说明看不清楚-91283472332w这种应该是返回最小的INT吗,是的
//字符串为空的话,不需要进行转换
if(str.empty()) return 0;
int len=str.size();
int sign=0;//符号位
long long total=0;//当前转换结果
int i=0;
while(str[i]==' '){
i++;
}
if(i==len) return 0;//字符串仅包含空白字符
sign=(int)(unsigned char)str[i];//c是第一个不为空格的字符
//45是负号,43是正
cout<<sign<<endl;
if(str[i]=='+'||str[i]=='-') i++;
while(i<len && isdigit(str[i])){
int pop=str[i]-'0';
cout<<"pop="<<pop<<" ";
if(sign=='-'){
if( total>INT_MAX/10 || (total==INT_MAX/10 && pop>8 )) {
return INT_MIN;
}
}
else{//sign不为负
if( total>INT_MAX/10 || (total==INT_MAX/10 && pop>7 )) {
return INT_MAX;
}
}
//if((sign=='+'&& total>INT_MAX/10) || (total==INT_MAX/10 && pop>7 && sign=='+')) return INT_MAX; 这样写是存在问题的
//if((sign=='-'&& total>INT_MAX/10) || (total==INT_MAX/10 && pop>8 && sign=='-')) return INT_MIN; 这样写是存在问题的。"-91283472332"这个测试用例不过,应该返回-2147483648
total=total*10+pop;
cout<<"total="<<total<<endl;
i++;
}
//假设该字符串中第一个非空格字符不是一个有效整数字符,或字符串仅包含空白字符
if(sign=='-') total=-total;
return total;
}
};