写在前面
对待刷题就跟对待喜欢的人一样,一天都不能断。
今日内容
vector扩容策略:
扩容的策略是 0.5倍倍增 capacity,然后做一个简单修正。
- 栈
栈是仅限在表尾进行插入和删除的线性表。先进后出,后进先出,即最先进入栈的元素最后出栈。
- 栈顶与栈底
栈顶带有栈顶指针,栈底是第一个元素存放的地方。一般只关心栈顶。
- 出栈与入栈
入栈:元素进入栈,栈顶指针加一,栈长加一。
出栈:元素pop出栈,栈顶指针减一,栈长减一。当然这得在栈里有元素的时候。
清空栈:一直出栈,知道栈内无元素。
- 栈的实现
可分为顺序表实现和链表实现。
顺序表实现:
```
#define DataType int // (1)
#define maxn 100005 // (2)
struct Stack { // (3)
DataType data[maxn]; // (4)
int top; // (5)
};
```
链表实现
```
typedef int DataType; // (1)
struct StackNode; // (2)
struct StackNode { // (3)
DataType data;
struct StackNode *next;
};
struct Stack {
struct StackNode *top; // (4)
int size; // (5)
};
```
概念千百遍,不如题目来一遍。
题目
剑指 Offer 31. 栈的压入、弹出序列
解题思路:
1、设置两个指针,i指向pushed数组当前的元素,j指向popped数组当前的元素
2、每次循环,将pushed数组当前元素入栈
3、判断popped当前元素是否与栈顶元素相同,相同则出栈,并将当前元素向后移动一位
4、如果pushed数组已经全部入栈,并且popped数组中仍有元素,则不合法,返回false,否则返回true;
class Solution {
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
int i = 0, j = 0;
stack<int> stk;
if (pushed.size() != popped.size()) return false; //长度不一致直接返回false
while (i < pushed.size() && j < popped.size()) {
stk.push(pushed[i++]); //pushed元素入栈
while (!stk.empty() && stk.top() == popped[j]) { //栈值与poped值比对
stk.pop();
j++;
}
if (i == pushed.size() && j < popped.size()) return false; //pushed元素已全部入栈,比对过后,j还有元素存在,返回false
}
return true;
}
};
946. 验证栈序列
解题思路:同上题一致
class Solution {
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
if (pushed.size() != popped.size()) return false;
int i = 0, j = 0;
stack<int> stk;
while (i < pushed.size()) {
stk.push(pushed[i++]);
while (!stk.empty() && stk.top() == popped[j]) {
stk.pop();
++j;
}
}
if (j < popped.size()) return false;
return true;
}
};
856. 括号的分数
解题思路:
1、定义一个递归函数,计算某段合格的平衡字符串区间的分数;
2、如果这段区间为2,则分数就是1;否则从左到右便利,遇到‘(’则计数器加1,否则计数器-1,当计数器为0时跳出循环;
3、这个时候要么得到的串是可以分割成两个单独的串,要么就是(A)这种情况,分别计算分数即可。
class Solution {
int scoreOfParentheses(const string& s, int l, int r) {
if (l + 1 == r) return 1; //一对括号
int cnt = 0;
int start = l;
while (1) {
cnt += (s[start] == '(' ? 1 : -1); //找到完整的()
++start;
if (cnt == 0) break;
}
if (start == r+1) return 2 * scoreOfParentheses(s, l+1, r-1); //只有一个平衡括号字符串
return scoreOfParentheses(s, l, start -1) + scoreOfParentheses(s,start, r); //左右两边都是平衡括号字符串,可以分别计算
}
public:
int scoreOfParentheses(string s) {
return scoreOfParentheses(s, 0, s.size()-1);
}
};
1190. 反转每对括号间的子串
解题思路:
1、定义一个函数,专门计算字符串从某个start位置开始得到的反转后的字符串
2、遍历左右字符串,遇到左括号(递归翻转括号内的字符串),右括号(返回当前字符串),和字符分别处理(字符串直接加上);
3、递归返回的过程,进行一次翻转,表示此次递归的情况下必定是一个括号内的串
class Solution {
int index;
string dfs(const string& s, int start) {
string ret;
for (index = start; index < s.size(); ++index) {
if (s[index] == '(') {
string st = dfs(s, index+1);
reverse(st.begin(), st.end());
ret += st;
} else if (s[index] == ')') {
return ret;
} else {
ret += s[index];
}
}
return ret;
}
public:
string reverseParentheses(string s) {
return dfs(s, 0);
}
};