目录
1、找出字符串中第一个只出现一次的字符
2、字符串相乘
3、反转字符串中的单词 III
4、反转字符串 II
5、字符串相加
6、验证回文串
7、字符串最后一个单词的长度
8、字符串中的第一个唯一字符
9、仅仅反转字母
1、找出字符串中第一个只出现一次的字符
#include <string>
#include <iostream>
using namespace std;int main()
{string words;while(cin >> words){bool IsFound = false;for(int i =0;i<words.size();i++){if(words.find_first_of(words[i]) == words.find_last_of(words[i])){cout << words.at(i) << endl;IsFound = true;break;}}if(!IsFound) cout << "-1" << endl;}return 0;
}
- find_first_of:从前向后找所给字符的位置(作用之一)
- find_last_of:从后向前找所给字符的位置(作用之一)
- 题解:同时从前和后两个方向寻找同一个字符,找到位置相等则该元素只出现一次,否则该元素在字符串中出现两次
2、字符串相乘
解法一:
#include <string>
class Solution {
public: //num1是乘数,num2是被乘数string multiply(string num1, string num2) {if(num1 == "0" || num2 == "0")//一个为0相乘结果为0return "0";string ans = "0";//初始化存放最终结果的对象int m = num1.size() - 1,n = num2.size() - 1;//m和n分别表示乘数和被乘数的下标for(int i = n ;i >= 0;i--)//从右向左循环遍历被乘数的每一位{ string curr;//curr作为每次的结果int add = 0;//add存储相乘时进位产生的数值for(int j = n;j > i ;j--)//在开始相乘前补零{curr.push_back(0);}int y = num2[i] - '0';//获取被乘数下标为i的字符的对应整数for(int j = m ;j >= 0;j--)//乘数每一位*被乘数{int x = num1[j] - '0';//获取乘数下标为j的字符的对应整数int product = x * y + add;//乘数的个/十/百...位 * 个/十/百...位 + 进位的数值curr.push_back(product % 10);//取出每次计算的最小位尾插进curradd = product / 10;//获取进位数值}while(add != 0)//for结束时add可能还有(1234*9,最后add = 10,还可以再尾插一个1){curr.push_back(add % 10);add /= 10;//将该加的都加上}reverse(curr.begin(),curr.end());//翻转字符串(8368->8638,string只有尾插没头插)for (auto &c : curr)//将ans每个字符转变为对应的整数?{c += '0';}ans = addstring(ans,curr);//每轮相乘的结果传递给add函数进行结果叠加,ans是字符串}return ans;//循环结束后返回最终答案}//("0","8638")string addstring(string& n1,string& n2){ //(i = 0,j = 3,add = 0,)int i = n1.size() - 1, j = n2.size() - 1, add = 0;//i和j是两个下标,add还是进位数值string ans;//每次相加的结果while(i>=0 || j>=0 || add!=0)//让能加的全加完故不用&&,两个数的每一位从右至左一次相加{int x = i >= 0 ? n1[i] - '0' : 0;//下标小于0,则没有什么可以加的了,将其赋值为0即可int y = j >= 0 ? n2[j] - '0' : 0;//下标大于等于0,则获取下标对应的数值int result = x + y + add;//每位相加的同时将之前进位的数值也加上ans.push_back(result % 10);//取结果的最小位尾插进ans,该位会被视为字符插入add = result / 10;//获取进位数值i--;//向前比较j--;}reverse(ans.begin(),ans.end());//翻转字符串for (auto &c : ans)//隐式转换,看下面的题解{c += '0';}return ans;}
};
题解:
- i初始值为n,每轮i--,但每轮j=n,且j>i,故每轮j循环多一次,被乘数的个/十百位逐渐变为0
- reverse是翻转字符串,reserve是开辟空间,前者要<algorithm>,后者要<string>
- push_back(2)在ans中存放的是ASCII码值为2的特殊字符而不是ASCII码值为50的'2',2 +'48' = 2 + 48 = 50 = '2'
解法二:
class Solution {
public://num1乘数,num2是被乘数string multiply(string num1, string num2) {if (num1 == "0" || num2 == "0") {return "0";}int m = num1.size(), n = num2.size();//m和n分别表示num1和num2的大小auto ansArr = vector<int>(m + n);//num1和num2相乘最大的空间是m+nfor (int i = m - 1; i >= 0; i--)//i和j分别表示乘数和被乘数的下标,从右至左逐位遍历{int x = num1[i] - '0';//字符转整数for (int j = n - 1; j >= 0; j--) {int y = num2[j] - '0';ansArr[i + j + 1] += x * y;//叠加}}for (int i = m + n - 1; i > 0; i--)//提取进位{ansArr[i - 1] += ansArr[i] / 10;//将当前坐标中的数的十位进位加到下一个坐标的存储的数值中ansArr[i] %= 10;//当前坐标存储只存储个位数}int index = ansArr[0] == 0 ? 1 : 0;//最高位是否为0,如果是则拷贝的下标从1开始,如果不是则从0开始string ans;//返回结果while (index < m + n) {ans.push_back(ansArr[index]);//向ans中尾插index++;}for (auto &c: ans)//方法一同理{c += '0';}return ans;}
};
3、反转字符串中的单词 III
解法一:
class Solution {
public:string reverseWords(string s) {string ret;int size = s.size();int i = 0;while (i < size) {int start = i;//子串的首下标start// 寻找第一个空格while (i < size && s[i] != ' '){i++;}//i的下标是空格的下标而不是空格前一个字符的下标// 将找到的单词逆序加入结果字符串for (int pos = i - 1; pos >= start; --pos)//空格前一个字符的下标是子串的尾下标pos{ret.push_back(s[pos]);}//在子串间插入空格,最后一个子串不进行尾插if(i < size){ret.push_back(' ');}i++; // 跳过当前的空格字符}return ret;}
};
解法二:
class Solution {
public:string reverseWords(string s) {int start = 0;for(int i = 0;i<s.size();i++)//i用来遍历整个数组下标{if(s[i+1]==' ' || i+1 == s.size())//即将到达空格或者边界{reverse(s.begin() + start,s.begin() + i + 1);//reverse的翻转范围是左闭右开的,空格刚好不会被翻转start = i + 2;//令start跳过空格}}return s;}
};
4、反转字符串 II
class Solution {
public:string reverseStr(string s, int k) {for (int i = 0; i < s.size(); i += (2 * k))//每2*k个字符为一段待翻转字符{if (i + k <= s.size())//i+k只要不小于size就证明还能再翻转k个,就将k个字符进行翻转{reverse(s.begin() + i, s.begin() + i + k);continue;}//不能翻转k个就将剩余的全部翻转reverse(s.begin() + i, s.begin() + s.size());//翻转[i,size)范围内的字符}return s;}
};
- 题目很唬人,但是将条件整合即可
5、字符串相加
class Solution {
public:string addStrings(string num1, string num2) {string ans = "";int i = num1.size() - 1,j = num2.size() - 1,add = 0;//i和j分别表示num1和num2的下标,add存放进位值while(i >= 0 || j >= 0 || add != 0){ int x = i >= 0 ? num1[i] - '0' : 0;int y = j >= 0 ? num2[j] - '0' : 0;int result = x + y + add;ans.push_back(result % 10 + '0');//直接在插入时解决之前要用for来解决的+='0'问题add = result / 10;//简简单单--i;--j;}reverse(ans.begin(),ans.end());return ans;}
};
- 跟字符串相乘处对字符的加操作一致,同时将最后for处理的内容直接在push_back处理了
6、验证回文串
解法一:
class Solution {
public:bool isPalindrome(string s) {string sgood;for (auto ch: s)//逐个读取字符串字符{if (isalnum(ch))//判断是否是字母或数字,是就插入sgood,不是就跳过,这样就不用管空格了{sgood += tolower(ch);}}string sgood_rev(sgood.rbegin(), sgood.rend());//翻转sgood的时将翻转结果存入sgood_revreturn sgood == sgood_rev;//返回判断新旧字符串是否相等的结果}
};
isalnum()
函数用于检查一个字符是否是字母或数字- tolower()函数检查
- 对string类类型字符串的+=说函数重载后的结果,表示尾插
- 利用范围for和auto关键字可以很好的遍历string类类型的字符串
解法二:
class Solution {
public:bool isPalindrome(string s) {string sgood;for (char ch: s) {if (isalnum(ch)) {sgood += tolower(ch);}}int n = sgood.size();int left = 0, right = n - 1;while (left < right) {if (sgood[left] != sgood[right]) {return false;}++left;--right;}return true;}
};
- 双指针?easy,拿下
解法三:
class Solution {
public:bool isPalindrome(string s) {//回文串左右两端的字母应该是对称的int n = s.size();int left = 0, right = n - 1;while (left < right) {while (left < right && !isalnum(s[left]))//跳过非数字和字母,如果s[left]处是数字和字母则!isalnum结果为假,否则为真{//当返回结果为真(s[left]处不是字母和数字就令left向右走到一个s[left]处是字母和数字的位置)++left;}//防止比较过程中出现的空字符打乱比较对象,只能让字母和数字参与比较while (left < right && !isalnum(s[right]))//同理{--right;}if (left < right)//如果此时两指针仍未相遇{if (tolower(s[left]) != tolower(s[right]))//判断双方此时所指向的字母(已转换为小写)是否相同{return false;//只要有一个不同就返回false}++left;//如果相同就令两指针继续向中间靠拢--right;}}return true;/循环结束则返回true}
};
- 遇到空格就继续向前走,因为空格不是参与比较的对象
7、字符串最后一个单词的长度
抽象题解:
#include<iostream>
using namespace std;int main() {string s;while(cin >> s);cout << s.size();return 0;
}
C++题解:
#include <iostream>
#include<string>
#include <algorithm>
using namespace std;int main()
{string a;getline(cin, a);int size = a.size(),count = 0;reverse(a.begin(),a.end());while(a[count]!=' ' && count < size)//注意考虑整个字符串就是一个单词的情况{count++;}cout<<count;
}
-
getline()
函数是用于从输入流中读取一行文本的函数
8、字符串中的第一个唯一字符
class Solution {
public:int firstUniqChar(string s) {for(int i = 0; i < s.size() ; i++){if(s.find(s[i]) == s.rfind(s[i])){return i;}}return -1;}
};
- find从左向右找子串第一次出现的位置,rfind从右向左找子串第一次出现的位置
find_first_of
正向查找在原字符串中第一个与指定字符串(或字符)中的某个字符匹配的字符,返回它的位置find_last
_of
逆向查找在原字符串中最后一个与指定字符串(或字符)中的某个字符匹配的字符,返回它的位置,逆向查找因为有'\0'所以最后一个有效字符的索引为1,'\0'为0
- string str=“abcdefab”;
- cout<<str.find_last_of(“wab”,5)<<endl;//从原串中下标为5开始逆向查找,首先f与待查子串每一字符比较,若有相同的就输出该字符在原串的下标。若一个都没有,就依次逆向比较,即e再与待查子串一一比较,直到原串的b与待查子串中的b相同,然后输出该b在原串的下标1
9、仅仅反转字母
解法一:
class Solution {
public:string reverseOnlyLetters(string s) {int n = s.size();int left = 0, right = n - 1;while (true) {while (left < right && !isalpha(s[left])) { // 判断左边是否扫描到字母left++;}while (right > left && !isalpha(s[right])) { // 判断右边是否扫描到字母right--;}if (left >= right)//双指针相遇或相遇后错开就终止循环{break;}swap(s[left], s[right]);//交换此时两个指针所指向的字母left++;right--;}return s;}
};
isalpha()
C++标准库函数,用于检查字符是否为字母字符,包含在<cctype>头文件
解法二:
class Solution {
public:string reverseOnlyLetters(string S) {int begin = 0,end=S.length()-1;while(begin<end){if(!isalpha(S[begin]))begin++;if(!isalpha(S[end])) end--;if(isalpha(S[begin])&&isalpha(S[end]))swap(S[begin++],S[end--]);}return S; }
};
~over~