目录
一、验证回文串
思路:
1、注:for(auto ch : s) -》指将s中每一个字符赋值给ch,ch的改变并不会影响s
但写为for(auto& ch : s) -》指将ch是s中每一个字符的引用,ch的改变影响s
2、将字符串中大写都转为小写或小写都转为大写,那判断是否为字母时,只需判断是否为小写字母即可,但这点最好的点在于比较字母时可以直接比较,因为都是统一的字母。
3、在走的过程中begin<end是因为如果一直没遇到字母和数字字符,不能让他一直走,走到尾要结束
代码如下:
class Solution {
public:
//判断是否为字母或数字
bool isCharOrNumber(char ch)
{
if ((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9'))
return true;
else
return false;
}
//验证回文串
bool isPalindrome(string s) {
//1、将字符串中所有的大写字母转成小写
for (auto& ch : s)
{//取别名才能改变ch
if (ch >= 'A' && ch <= 'Z')
{
ch += 32;
}
}
//2、用快排的思路进行比较
int begin = 0, end = s.size() - 1;
while (begin < end)
{//比较的大前提是begin < end
while (begin < end && !isCharOrNumber(s[begin]))
++begin;//若不是字母或数字则begin++往后找
while (begin < end && !isCharOrNumber(s[end]))
--end;//若不是字字母或数字则end--往前找
//找到字母或数字了则开始比较
if (s[begin] != s[end])
{
return false;
}
else
{
++begin;
--end;
}
}
return true;
}
};
二、字符串相加
题目的意思是字符串变为整数相加后又变为字符串的形式 ,那这个字符串是多少?不允许字符串直接全转换为整形后相加,因为如果这个字符串很长,转换是存不下的
先给代码后说思路:
class Solution {
public:
string addString(string num1, string num2) {
//end1和end2从两个字符串的最后一位开始往前比
int end1 = num1.size() - 1, end2 = num2.size() - 1;
int next = 0;//用来保存是否进一位
string retstr;//此字符串用来保存结果并返回
while (end1 >= 0 || end2 >= 0)
{//两个字符串都结束了才算结束
int val1 = 0, val2 = 0;
if (end1 >= 0)//>=0说明没走完,因为存在一个字符串走完另个字符串没走完的情况
val1 = num1[end1] - '0';//将字符转换为数字
if (end2 >= 0)
val2 = num2[end2] - '0';
int ret = val1 + val2 + next;//转换成的数字相加
if (ret > 9)
{
ret -= 10;//>9则需要进位
next = 1;//进位出来的1
}
else
{//加出来的那一位ret<=9则无需进位,next=0
next = 0;
}
//retstr.insert(retstr.begin(), '0' + ret);
retstr += (ret + '0');//再把这一位转换为字符尾插到ret末尾
--end1;//--来进行前一位的相加
--end2;
}
if (next == 1)
{//在最后一次若next==1,尾插一个'1'
//retstr.insert(retstr.begin(), '1');
retstr += '1';
}
//因为之前是尾插的,那正确的字符串应该逆置
reverse(retstr.begin(), retstr.end());
return retstr;
}
};
思路:
对于两个字符串从后往前一位一位进行相加,当然,字符不能直接相加,我们先把每一位对应的字符先转换为数字相加,如果加出来的这一位>9,则next=1(next用来表示是否进位) ,若<9,则next=0,当前一位的对应字符相加时就要加上next,进不进位就由next来区分了
代码中的剖析:
①、while结束条件是end1 >= 0 || end2 >= 0 因为给的字符串可能一个长一个短,只有长的也结束了相加才结束,所以用或,end1和end2原来给的是字符串最后一个字符的下标,若end1<0说明end1对应的字符串走完了,end2同理
②、在走的过程中要判断end1和end2是否>=0,因为存在一个字符串长一个字符串短的情况,长的没走完还要进入循环中,短的字符串走完了就不用计算了,所以如果>=0说明还没走完,要继续计算
③、字符的插入方式:
1、用insert来头插,但头插需要每次都向后移动,现有几个元素就需移几次,每次都头插一个元素,有一个元素需移动一次,两个元素需要移动两次,n个元素需要移动n次,1+2+...+n,故时间复杂度:O(N*N),效率不好
2、每插入一个元素都尾插,最后全尾插完再用algorithm中的reverse实现(需#include<algorithm>),时间复杂度:O(N),故推荐此方式
下面给出一个例子:
拓展知识:
字符串相加可用于高精度算法的计算
在一些特殊的计算场合中,经常会算到小数点后几百位甚至更多,当然也可能是大几千亿几百亿的数字。我们把这类数字统称为高精度数字。高精度算法就是计算机对于超大数据的一种模拟加减乘除阶乘开方等运算。
解决方法:当一个数据很大时,我们无法使用整数类型存储,故我们把他当成一个字符串输入,这样就可以输入一个很长的数,利用字符串相加相乘等解决这类问题
三、杨辉三角
题述:
给定一个非负整数 numRows,生成杨辉三角的前 numRows行。
示例:
题中已给:
class Solution {
public:
vector<vector<int>> generate(int numRows) {
}
};
知识点:理解vector<vector<int>>vv
思路:
对于杨辉三角的实际状态,除了1外,每个数=上一行同下标的数+上一行同下标-1的数,而每一行的首元素和尾元素都会是1,利用这个规律就好求解了
代码如下:
class Solution {
public:
vector<vector<int>> generate(int numRows) {
vector<vector<int>> vv;
vv.resize(numRows);//开辟numRows个(行)
for (size_t i = 0; i < numRows; ++i)
{
vv[i].resize(i + 1);//每一行对应开i+1个
vv[i][0] = 1;//每一行的第一个元素为1
vv[i][vv[i].size() - 1] = 1;//每一行的最后一个元素为1
}
for (size_t i = 0; i < vv.size(); ++i)
{
for (size_t j = 0; j < vv[i].size(); ++j)
{
if (vv[i][j] != 1)
{//不是首尾元素的,则等于上一行同列下标+同列下标-1的值
vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
}
}
}
return vv;
}
};
四、最小栈
题述:
设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
- push(x)—— 将元素 x 推入栈中。
- pop()—— 删除栈顶的元素。
- top()—— 获取栈顶元素。
- getMin()—— 检索栈中最小元素
输入:["MinStack","push","push","push","getMin","pop","top","get"]
[[ ],[-2],[0],[-3],[ ],[ ],[ ],[ ]]
输出:
[null,null,null,null,-3,null,0,-2]
题中已给:
class MinStack { public: /* initialize your data with structure here */ MinStack() { } void push(int x) { } void pop() { } int top() { } int getMin() { } };
思路:
①、错误思路:
用两个栈,假设为栈A和栈B,A用来把所有元素一个个入栈,B用来存最小的元素
假如A中要存数据5 2 1 6,那么初始先入5到B,再考虑2,2比5小,删除B的栈顶,再把2入B,再考虑1,1比2小,删除B的栈顶,再把1入B,再考虑6,6没2小,不入B,那么B中最小的就是栈顶了
但是若删除A中数据呢,B也受影响?栈一定是从栈顶开始删的,删除完后再找最小的元素就找不到了,因为之前的都被删除了。但是可以再遍历一遍A,再找最小元素,但这不符合题目规定的常数时间了,故这种方法不可以
②、正确思路:
用两个栈,假设为栈A和栈B,跟错误思路的区别就是,B中不是只存最小的元素,而是在每次比较中,只要比B当前的栈顶元素小或等于的都入B,不删除之前的元素,那么再删除栈顶的时候,只有当B中和A中的元素相同时,才会删除B的栈顶,删除完后的栈顶还是当前最小的元素
代码如下:
//最小元素
class MinStack {
public:
/* initialize your data with structure here */
MinStack() {}//因为栈是自定义类型,他有自己的构造函数,故构造函数可不写
void push(int x) {
_st.push(x);//_st的所有数据都会入栈
if (_minst.empty() || _minst.top() >= x)
{//只有当没数据或栈顶的元素>=要入的数据时,才会入_minst
//重复的最小元素也要入_minst,因为假设有0 1 0三个数先后入_st,那如果
// 不重复入minst,_minst只有0,当删除0时,_minst为空,再访问最小元素就
// 没有了,但理应还返回0,所以重复的元素也要入栈
_minst.push(x);
}
}
void pop() {
if (_st.top() == _minst.top())
_minst.pop();
_st.pop();
}
int top() {
return _st.top();
}
int getMin() {
return _minst.top();
}
stack<int> _st;//所有数据都入栈
stack<int> _minst;//每次的更小值入栈
};
五、栈的压入、弹出序列
题述:
题意是入栈的顺序是固定的,但出栈有好几种顺序,因为可以边进边出,pushV储存的入栈的元素,popV指的是出栈的元素
思路:
在已知出栈顺序的前提下,定义一个栈st,开始先入一个数据到st中,入完一个数据立即比较,比较跟出栈顺序的第一个元素是否相等,相等则出栈,然后比较下一元素,不相等则再入数据到栈中
注意①:出栈是个while循环操作,条件是栈不为空且st中的栈顶=此时popV指向的当前元素才行,栈不为空才出栈因为可能在连续出栈的过程中栈为空了,这时应该再入数据
注意②:入栈直到栈数据全入完了才终止,那么入完了就可以判断顺序是否合法,此时只要栈中还有数据就是不合法,没数据才合法,因为只有出栈入栈的顺序合法才会为空
代码实现:
class Solution {
public:
bool IsPopOrder(vector<int>pushV, vector<int>popV) {
//栈来模拟进出 (用vector类似于用了c语言中的数组)
stack<int> st;
int pushi = 0, popi = 0;//入栈和出栈的下标
while (pushi < pushV.size())//当走到尾就可判定了,但在这之前都要入栈
{
st.push(pushV[pushi]);//入数据
++pushi;
//入完一个数据就要立即跟已给的出栈顺序比较
//因为可能要连续出,所以用while循环
while (!st.empty() && st.top() == popV[popi])
{
//1、出到空就不能再出了,要退出while
//2、若栈顶和已给的出栈顺序的对应位置相同,则进入while
st.pop();
++popi;
}
}
//只有入栈的数据全部进入,且最后栈为空就是合法的顺序
return st.empty();//若为空,则为合法的顺序
}
};