前言
这里的题目大多是用c++写的。
题目
仅仅反转字母
原题链接:仅仅反转字母
my version:
class Solution {
public:
string reverseOnlyLetters(string s) {
int begin = 0,end = s.size() - 1;
while(begin < end)
{
while(begin<end&&!isalpha(s[begin]))
{
begin++;
}
while(begin<end&&!isalpha(s[end]))
{
end--;
}
swap(s[begin],s[end]);
begin++;
end--;
}
return s;
}
};
字符串中的第一个唯一字符
原题链接:字符串中的第一个唯一字符
计数法:
class Solution {
public:
int firstUniqChar(string s) {
int arr[130] = {0};
for(auto x : s)
{
arr[x-'0']++;
}
int i = 0;
for(auto x : s)
{
if(arr[x-'0'] == 1)
return i;
i++;
}
return -1;
}
};
翻转字符串
原题链接: 翻转字符串
版本一:
class Solution {
public:
void reverseString(vector<char>& s) {
int left = 0,right = s.size() -1;
while(left<right)
{
char tmp = s[left];
s[left] = s[right];
s[right] = tmp;
// swap(s[left],s[right]);这边交换可以直接用c++给的swap
left++;
right--;
}
}
};
这里不能用指针
版本二:
class Solution {
public:
void reverseString(vector<char>& s) {
reverse(s.begin(),s.end());
}
};
验证回文串
原题链接:验证回文串
自己做的:
class Solution {
public:
bool isPalindrome(string s) {
string s1(s.size(),'\0');
string::iterator it = s.begin();
int i = 0;
while (it != s.end())
{
if (isalnum(*it))
{
s1[i++] = *it;
}
it++;
}
transform(s1.begin(), s1.end(), s1.begin(), ::tolower);
int sz = 0;
while (s1[sz] != '\0')
{
sz++;
}
string s2(s1,0,sz);
s1 = s2;
reverse(s2.begin(), s2.end());
if (s1.compare(s2) == 0)
return true;
else
return false;
}
};
做这道题,让我深刻意识到以下几点:
- string类的字符串,如果要判断是否相同,它们的’\0’也要算进去
- string类的字符串,它们的size(),length()包括’\0’
那么如果有’\0’存在,我们该怎么求有效字符的长度呢?
我们可以用到string类的一个函数:c_str()
void Test2()
{
string s(10,'\0');
//s.reserve(10);
s[0] = 'a';
int lenth = strlen(s.c_str());//
cout << s << endl;
cout << s.size() << endl;
cout << lenth << endl;
//cout << s.capacity() << endl;
//s.reserve(200);
//cout << s.capacity() << endl;
}
官方版本:
🚗方法一:筛选 + 判断
class Solution {
public:
bool isPalindrome(string s) {
string sgood;
for (char ch: s) {
if (isalnum(ch)) {
sgood += tolower(ch);//可以用运算符重载+=
}
}
string sgood_rev(sgood.rbegin(), sgood.rend());//直接用rbegin反转
return sgood == sgood_rev;//运算符重载==判断是否相等
}
};
🚗方法二:双指针
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;
}
};
🚗方法三:在原字符串上直接判断
我们直接在原字符串 sss 上使用双指针。在移动任意一个指针时,需要不断地向另一指针的方向移动,直到遇到一个字母或数字字符,或者两指针重合为止。也就是说,我们每次将指针移到下一个字母字符或数字字符,再判断这两个指针指向的字符是否相同
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])) {
++left;
}
while (left < right && !isalnum(s[right])) {
--right;
}
if (left < right) {
if (tolower(s[left]) != tolower(s[right])) {
return false;
}
++left;
--right;
}
}
return true;
}
};
把字符串转换成整数
原题链接:把字符串转换成整数
my version:
class Solution {
public:
bool IsLegal(string str)
{
for(auto ch : str)
{
if((ch>'9'||ch<'0'))
return false;
}
return true;
}
int StrToInt(string str) {
if(str.size() == 0)
return 0;
if(((str[0]!='+'&&str[0]!='-')&&(str[0]>'9'||str[0]<'0')))
return 0;
string s1(str,1);
if(IsLegal(s1) == false )
return 0;
int lenth = str.size();
if(str[0]=='+'||str[0]=='-')
lenth--;
int sum = 0;
string s2 = (str[0]<='9'&&str[0]>='0') ? str:s1;
for(auto ch : s2)
{
int x = ch - '0';
sum+=x*pow(10,lenth - 1);
lenth--;
}
if(str[0]=='-')
sum = -sum;
return sum;
}
};
other version:
class Solution {
public:
int StrToInt(string str) {
int ans = 0;int isplus = 1;
for(char ch:str){
if(isalpha(ch))
{
return 0;
}if (ch == '+' || ch =='-')
{
isplus = (ch == '+') ? 1 : -1;
}
if(isdigit(ch))
{
ans = ans*10+ch-'0';
}
}return isplus*ans;
}
};
这个版本厉害!
字符串最后一个单词的长度
原题链接:字符串最后一个单词的长度
my version:
#include <iostream>
using namespace std;
int main() {
string s;
getline(cin,s);//这样可以输入空格
int len;
if(s.rfind(' ')==string::npos)
len = s.size();
else
len = s.size()-s.rfind(' ') - 1;
cout<<len;
}
字符串相加
原题链接: 字符串相加
my version:
class Solution {
public:
string addStrings(string num1, string num2) {
//假设num1的长度最小
string s;
if(num1.size()>num2.size())
{
swap(num1,num2);//交换一下
}
int end1 = num1.size() - 1,end2 = num2.size() - 1;//end1<=end2
int tmp = 0,next = 0;
char ch;
while(end2>=0)
{
if(end1>=0)
{
tmp = num1[end1]-'0'+num2[end2] - '0'+next;
next = 0;
if(tmp>9)
next = 1;
tmp%=10;
ch = tmp+'0';
s+=ch;
}
else
{
tmp = num2[end2] - '0' + next ;
next = 0;
if(tmp>9)
next = 1;
tmp%=10;
ch = tmp+'0';
s+=ch;
}
end1--;
end2--;
if(end2==-1&&next==1)
{
s+='1';
}
}
reverse(s.begin(),s.end());
return s;
}
};
优化一下:
class Solution {
public:
string addStrings(string num1, string num2) {
//假设num1的长度最小
string s;
if(num1.size()>num2.size())
{
swap(num1,num2);//交换一下
}
int end1 = num1.size() - 1,end2 = num2.size() - 1;//end1<=end2
int tmp = 0,next = 0;
int _num1;
char ch;
while(end2>=0)
{
if(end1>=0)
_num1 = num1[end1]-'0';
else
_num1 = 0;
tmp = _num1+num2[end2] - '0'+next;
next = 0;
if(tmp>9)
next = 1;
tmp%=10;
ch = tmp+'0';
s+=ch;
end1--;
end2--;
if(end2==-1&&next==1)
{
s+='1';
}
}
reverse(s.begin(),s.end());
return s;
}
};
其实这里while的判断条件改为二者都>=0就行了。
这样就不用可以去比较num1和num2的长度
反转字符串 II
原题链接: 反转字符串 II
my version:
class Solution {
public:
string reverseStr(string s, int k) {
int left = 0, right = k - 1;
int count = 0;
for (int i = 0;i<s.size(); i++)
{
count++;
if (count == 2 * k)
{
int tmp1 = left,tmp2 = right;
while (tmp1 < tmp2)
{
swap(s[tmp1++], s[tmp2--]);
}
left+=2*k;
right = left + k - 1;
count = 0;
}
int len = s.size() - left;
if (len < k)
{
right = s.size() - 1;
while (left < right)
{
swap(s[left], s[right]);
left++;
right--;
}
break;
}
if(len<2*k&&len>=k)
{
while (left < right)
{
swap(s[left], s[right]);
left++;
right--;
}
break;
}
}
return s;
}
};
official version:
class Solution {
public:
string reverseStr(string s, int k) {
int n = s.length();
for (int i = 0; i < n; i += 2 * k) {
reverse(s.begin() + i, s.begin() + min(i + k, n));
}
return s;
}
};
看完后感觉自己的作法简直是猿古人😅
反转字符串中的单词 III
原题链接:反转字符串中的单词 III
my version:
lass Solution {
public:
string reverseWords(string s) {
size_t begin = 0,end = s.find(' ');
while(string::npos!=end)
{
reverse(s.begin()+begin,s.begin()+end);
begin = end+1;
end = s.find(' ',end+1);
}
reverse(s.begin()+begin,s.end());
return s;
}
};
字符串相乘
原题链接:字符串相乘
my version:
class Add {
public:
string addStrings(string num1, string num2) {
//假设num1的长度最小
string s;
if (num1.size() > num2.size())
{
swap(num1, num2);//交换一下
}
int end1 = num1.size() - 1, end2 = num2.size() - 1;//end1<=end2
int tmp = 0, next = 0;
int _num1;
char ch;
while (end2 >= 0)
{
if (end1 >= 0)
_num1 = num1[end1] - '0';
else
_num1 = 0;
tmp = _num1 + num2[end2] - '0' + next;
next = 0;
if (tmp > 9)
next = 1;
tmp %= 10;
ch = tmp + '0';
s += ch;
end1--;
end2--;
if (end2 == -1 && next == 1)
{
s += '1';
}
}
reverse(s.begin(), s.end());
return s;
}
};
class Solution {
public:
string multiply(string num1, string num2) {
int end1 = num1.size() - 1, end2 = num2.size() - 1;
string sum("");
Add add;
for (int i = end1,mu = 0; i >= 0; i--,mu++)
{
string s("");
int next = 0;
for (int j = end2; j >= 0; j--)
{
int x1 = num1[i] - '0';
int x2 = num2[j] - '0';
int ref = ((x1 * x2) + next)%10;//要插入stirng的数字
next = ((x1 * x2) + next) / 10;//下回合要加的
s += ref + '0';
}
if (next != 0)
s += next + '0';
reverse(s.begin(), s.end());
//接下来要追加0
for (int k = 0;k < mu; k++)
{
s += '0';
}
sum = add.addStrings(sum, s);
}
if(sum[0]=='0')
sum = '0';
return sum;
}
};
只出现一次的数字
原题链接:只出现一次的数字
异或作法:
class Solution {
public:
int singleNumber(vector<int>& nums) {
int val = 0;
for(auto x:nums)
{
val^=x;
}
return val;
}
};
杨辉三角
原题链接:杨辉三角
class Solution {
public:
vector<vector<int>> generate(int numRows) {
vector<vector<int>> vv;
//首先我们先开辟需要的二维数组空间
vv.resize(numRows);//用resize主要是为了初始化为0
int i = 0;
for(i = 0;i<numRows;i++)
{
vv[i].resize(i+1);
vv[i][0] = vv[i][vv[i].size()-1] = 1;//每一行的首尾初始化为1
}
//开始将其余赋值
for(i = 0; i<numRows;i++)
{
for(int j = 0;j<vv[i].size();j++)
{
if(vv[i][j]==0)
{
vv[i][j] = vv[i-1][j]+vv[i-1][j-1];
}
}
}
return vv;
}
};
删除有序数组中的重复项
原题链接:删除有序数组中的重复项
思路;
MyCode;
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int tmp = nums[0],count = 0, k = 0;
for(int i = 1 ;i<nums.size();)
{
if(nums[i]==tmp)
{
count++;
nums.erase(nums.begin()+i);//删后不能再++
}
else
{
tmp = nums[i];
count = 0;
}
if(count == 0)
{
k++;
i++;
}
}
return nums.size();
}
};
这道题我感觉题目表述不是很好,返回唯一元素的个数,我以为是原数组中唯一元素的个数,
但实际,就是返回删完后的数组的长度(因为此时重复项都删完肯定都唯一了🤣)
只出现一次的数字 II
原题链接:
只出现一次的数字 II
法一:依次确定每一个二进制位
class Solution {
public:
int singleNumber(vector<int>& nums)
{
int ans = 0;
for(int i = 0;i<32;i++)
{
int sum = 0;
for(int e:nums)//遍历每一位二进制位,&1后将该位所有的0/1情况相加
{
sum+=((e>>i)&1);
}
if(sum%3)//要么sum%3==1,要么==0,如果不等于0,说明该位应该是1
{
ans|=(1<<i);
}
}
return ans;
}
};
二叉树的层序遍历
原题链接:二叉树的层序遍历
队列法
Code:
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*> q;//创建一个队列存入每一层的节点
int levelsize = 0;
if(root)//如果不为空
{
q.push(root);
levelsize++;
}
vector<vector<int>> vv;
while(!q.empty())
{
vector<int> v;
while(levelsize--)
{
TreeNode* front = q.front();
q.pop();//出队列
//接下来开始入下一个头节点的数据
if(front->left)
q.push(front->left);
if(front->right)
q.push(front->right);
v.push_back(front->val);
}
vv.push_back(v);
levelsize = q.size();
}
return vv;
}
};
思路:
我们创建一个队列,这个队列的作用是什么呢?
这个队列的作用主要就是先存入二叉树的一层数据,然后又负责将刚刚存入那一层的数据给出队列,然后再入下一层的队列,直到队列为空。
这中间的具体细节是什么呢?
当我们在出一个层的数据时,我们怎么知道该层到底有多少个数据呢?
实际上,在我们出某一层的数据同时,我们也在入下一层的数据,当该层的数据出完后,下一层的数据也入完了。
如上图中,
入第一层:1先入进去
出第一层和入第二层:此时1指向了2和3,当1出完后,2和3随后入队列,刚刚好第二层入完了。
出第二层和入第三层:
1.先出2,此时2指向了4和空, 4再入队列,此时队列中的数据为3 4
2.再出3,3指向了5和6,5和6再入队列,此时第二层出完了,正好第三层也入完了。
所以我们总结一下,这就是一个出n层入n+1层的循环,循环次数为n层中的数据个数
逆波兰表达式求值
原题链接:逆波兰表达式求值](https://leetcode.cn/problems/evaluate-reverse-polish-notation/description/)
Code:
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> s;
for(int i = 0;i<tokens.size();i++)
{
//如果为数字,就先入栈等待遇到运算符计算
string& str = tokens[i];
if(!("+" == str || "-" == str || "*" == str || "/" == str))
{
s.push(atoi(str.c_str()));
}
else//此时就要开始计算了
{
int right = s.top();
s.pop();
int left = s.top();
s.pop();
switch(str[0]){
case '+':
s.push(left+right);
break;
case '-':
s.push(left-right);
break;
case '*':
s.push(left*right);
break;
case '/':
s.push(left/right);
break;
default:
break;
}
}
}
return s.top();
}
};
中缀表达式->后缀表达式思路: