
༺ 个人主页 · 纪念229 ༻
༒专栏目录:《算法》༒
༒专栏目录:《C++》༒
༒专栏目录:《MySQL数据库》༒
༒专栏目录:《前端开发》༒
༺世上本没有路,走的人多了自然就有了༻
本篇文章主要讲述的是有关string数组的应用,希望对你有所帮助
题目链接:
1.电话号码字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
具体意思是给你个看了个号码按键数字按键下有对应的字符集合(字符串)要求给出一个数字字符串根据数字字符字将给出的不是一个区域的字符相互组合可以有多少个组合
看到数字下有字符集合我们就因该想到string数组该题从下标0开始到下标9下标0和1题目没要求组合我们定义为空
这种string数组对应组合的题解法就是for循环加递归(递归回溯)
具体代码
c
class Solution {
// 递归回溯(利用for循环加递归解决一一组合问题)
private:
// 建立数字到字母的映射,注意0和1没有对应的字母
const string letterMap[10] = {
// const string letterMap =
// {这里不是string每个元素只能装字符是string数组每个元素可以装一个字符串
"", // 0
"", // 1
"abc", // 2
"def", // 3
"ghi", // 4
"jkl", // 5
"mno", // 6
"pqrs", // 7
"tuv", // 8
"wxyz" // 9
};
vector<string> result; // 存放最终结果
string path; // 存放当前路径(及当前的字母组合)
// index记录当前正在遍历digits中的第几个字符
void backtracking(const string& digits, int index) {
// 终止条件:如果当前遍历的索引等于 digits的长度,说明找到一个完整组合
if (index == digits.size())
{
result.push_back(path);
return;
}
// 获取当前遍历到的数字字符对应的整数
int digit = digits[index] - '0';
// 获取该数字对应的字符串
string letters = letterMap[digit];
// 遍历所有数字对应的字母
for (int i = 0; i < letters.size(); i++)
{
path.push_back(letters[i]);
backtracking(
digits,
index +
1); // 这里利用for循环和递归将string数组中的每个元素里的字符一一组合
path.pop_back(); // 清空path以防下一次组合时出错
}
}
public:
vector<string> letterCombinations(string digits) {
// 清空历史数据(为多次测试安全)
result.clear();
path.clear();
// 如果输入为空,直接返回空数组
if (digits.size() == 0)
{
return result;
}
// 从第0个字符开始递归
backtracking(digits, 0);
return result; // 最后返回结果
}
};
首先我们在访问限定符定义一个string数组LetterMap将0~9对应的字母字符串定义好0,和1按题意字符串为空
我们知道struct没写访问限定符的东西就默认是public我们在函数backtracking上定义vector 的result对象存每个组合的元素 string path存组合的字符串
c
void backtracking(const string& digits, int index) {
// 终止条件:如果当前遍历的索引等于 digits的长度,说明找到一个完整组合
if (index == digits.size())
{
result.push_back(path);
return;
}
// 获取当前遍历到的数字字符对应的整数
int digit = digits[index] - '0';
// 获取该数字对应的字符串
string letters = letterMap[digit];
// 遍历所有数字对应的字母
for (int i = 0; i < letters.size(); i++)
{
path.push_back(letters[i]);
backtracking(
digits,
index +
1); // 这里利用for循环和递归将string数组中的每个元素里的字符一一组合
path.pop_back(); // 清空path以防下一次组合时出错
}
}
c
// 终止条件:如果当前遍历的索引等于 digits的长度,说明找到一个完整组合
if (index == digits.size())
{
result.push_back(path);
return;
}
这个我到时候解释
backtracking函数给了digit和index digit是系统给的数字字符串 index开始是0作为下标遍历digit
c
// 获取当前遍历到的数字字符对应的整数
int digit = digits[index] - '0';
// 获取该数字对应的字符串
string letters = letterMap[digit];
获取digit第某个的字符将其减'0'得到的数字作为LeeterMap下标
我们定义一个string对象leeters将LeeterMap下标所指向的字符串给它
c
// 遍历所有数字对应的字母
for (int i = 0; i < letters.size(); i++)
{
path.push_back(letters[i]);
backtracking(
digits,
index +
1); // 这里利用for循环和递归将string数组中的每个元素里的字符一一组合
path.pop_back(); // 清空path以防下一次组合时出错
}
我们调用当前的leeters的size()作为for循环的条件将tmp对象调用push_back放入leeters第i个字符我们继续调用backtrack(digit, index + 1)继续递归(由于递归index会一直++(临时对象))直到index == digit.size()
c
if (index == digits.size())
{
result.push_back(path);
return;
}
我们将path(组合好的字符串)push_back到result上(对于result来说path就是自己的一个元素)
返回然后函数调用 path的pop_back将插入字符删除直到删完为止继续第一个for循环++i我们继续调用递归直到遇到index == digie.size()将组合好的字符串放入result中,递归循环结束组合结束result就得到了digit数字字符串每个数字字符所对应的字母字符的所有互相组合方式
2.最小栈

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
c
//最小栈这个类利用的是它的两个成员变量一个普通栈st和辅助栈min_st(辅助栈要求栈顶是最小值,取得栈中最小值也从这里开始取)
//这种类题一般给成员函数不给成员变量需要我们自己设计
class MinStack {
private:
stack<int> st;
stack<int> min_st;
public:
MinStack() {
//什么都么都不用写st与min_st默认构造就是空
}
void push(int value) {
//如果辅助栈(最小栈)为空或要插入的数据小于等于辅助栈栈顶元素时我们就将该值入辅助栈
if(min_st.empty() || value <= min_st.top())
{
min_st.push(value);
}
//无论什么时候都要将栈入栈
st.push(value);
}
void pop() {
//如果成员变量栈顶元素与辅助栈的栈顶元素相等时就将辅助栈的栈顶元素删除
if(st.top() == min_st.top())
{
min_st.pop();
}
st.pop();
}
int top() {
//这里的top是取栈顶元素
return st.top();
}
int getMin() {
//这里getMin是取辅助栈栈顶元素(也就是栈中的最小值)
return min_st.top();
}
};
/**
* Your MinStack object will be instantiated and called as such:
* MinStack* obj = new MinStack();
* obj->push(value);
* obj->pop();
* int param_3 = obj->top();
* int param_4 = obj->getMin();
*/
这里的最小栈的意思是除了普通的栈我们还要定义一个辅助栈该栈的栈顶元素是普通栈中的最小值
我们会看到该题没有成员变量需要我们自己写我们写一个访问限定符private里面定义容器对象st和min_st(辅助栈)
c
private:
stack<int> st;
stack<int> min_st;
由于成员变量都是STL里的容器对象所以我们可以不写默认构造(stack容器的默认构造已经设计好了)
其它的设计与栈的基本功能都差不多这里我们就讲解一下要用到min_stack辅助栈的成员函数
c
void push(int value) {
//如果辅助栈(最小栈)为空或要插入的数据小于等于辅助栈栈顶元素时我们就将该值入辅助栈
if(min_st.empty() || value <= min_st.top())
{
min_st.push(value);
}
//无论什么时候都要将栈入栈
st.push(value);
}
这里入栈如果是普通栈就直接将stack对象st调用push_back
这里我们如果普通栈刚开始入栈(辅助站为空)我们直接将min_st调用push_back如果不为空我们要判断参数是否小于等于(等于是因为pop时若是pop的是最小元素但是普通栈里这个元素还有我们如果不将相等的元素入辅助栈就会出错)辅助栈的栈顶元素如果小于就将该参数入辅助栈
c
void pop() {
//如果成员变量栈顶元素与辅助栈的栈顶元素相等时就将辅助栈的栈顶元素删除
if(st.top() == min_st.top())
{
min_st.pop();
}
st.pop();
}
这里如果普通栈的栈顶元素与辅助栈的栈顶元素相同时我们要将min_st调用pop_back()出栈
c
int getMin() {
//这里getMin是取辅助栈栈顶元素(也就是栈中的最小值)
return min_st.top();
}
这个是返回min_st调用top函数返回栈里的最小值
3.栈的弹出压入序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。
这里其实就是判断压入和弹出是否合理
合理就是压入和出栈循序是合理的
c
//检测栈的压入、弹出序列(利用辅助栈模拟入栈出栈过程每次压入过后都要判断辅助栈栈顶元素是否与弹出序列中下标指向的元素相等如果相等将辅助栈pop下标++继续判断辅助栈栈顶元素与弹出序列下标所指的元素相等(不相等结束判断辅助栈为空结束判断))
class Solution {
public:
bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {
//首先两序列数目不同压入弹出序列不配对
if(pushV.size() != popV.size())return false;
//利用辅助栈实现压入弹出栈(最后辅助栈为空说明配对(true)不为空说明不配对(false))
stack<int> st;
//利用for循环遍历压入
int j = 0;//用一个下标作为弹出序列的下标匹配成功下标++
for(auto e : pushV)
{
st.push(e);
//每次压入都要判断辅助栈栈顶元素是否与弹出序列下标指向的元素相等且辅助栈不能为空利用whlie循环遍历直到辅助栈为空为止
while(!st.empty() && st.top() == popV[j])
{
st.pop();
j++;
}
}
return st.empty();//最后辅助栈为空就说明配对成功不为空就说明配对失败
}
};
首先如果压入和弹出对象的数目不同就说明不符合压入弹出顺序直接返回false
if(pushV.size() != popV.size())return false;
这里我们也要定义一个辅助栈我们利用范围for将压入栈的数据一一插入辅助栈中(在我们在外面定义一个下标j遍历弹出顺序)我们在范围for写一个whlie循环
条件是辅助栈不为空且辅助栈的栈顶元素与弹出的下标所指向的元素相等我们就将辅助栈调用pop函数将j++循环判断
stack<int> st;
int j = 0;
c
for(auto e : pushV)
{
st.push(e);
//每次压入都要判断辅助栈栈顶元素是否与弹出序列下标指向的元素相等且辅助栈不能为空利用whlie循环遍历直到辅助栈为空为止
while(!st.empty() && st.top() == popV[j])
{
st.pop();
j++;
}
}
return st.empty();
最后返回st调用empty判断st对象不为空说明弹出和压入顺序不对返回false如果st对象调用empty为空就说明弹出和压入顺序对返回true
文章到此就告一段落,希望对你有所帮助,感谢观看!