2021/3/8 132. 分割回文串 II(dp)
与昨天的题目不同,数据范围不一样,最后需要求得的答案也不同;这里主要还是需要动态规划,而且需要两次
1、参考昨天的题目,首先求出字符串任意位置i到j是否为回文串,做法与上一题相同;
2、为了求最小的分割数,需要一次dp,参考代码
class Solution {
public:
int minCut(string s) {
int n = s.size();
vector<vector<int>> g(n, vector<int>(n, true));
for(int i = n - 1; i >= 0; i--){
for(int j = i + 1; j < n; j++){
g[i][j] = ((s[i] == s[j]) && (g[i + 1][j - 1]));
}
}
vector<int> dp(n, INT_MAX);
for(int i = 0; i < n; i++){
if(g[0][i]) dp[i] = 0;
else{
for(int j = 0; j < i; j++){
if(g[j + 1][i])
dp[i] = min(dp[i], dp[j] + 1);
}
}
}
return dp[n - 1];
}
};
2021/3/9 1047. 删除字符串中的所有相邻重复项(栈)
(我是个傻子吧)明明数据范围只有20000,经过了六次tle之后终于发现在最后由栈内元素生成字符串时,我用的是str = str + st[i] ,这样复杂度就是20000 * 20000了。简单的用栈模拟即可。
class Solution {
public:
string removeDuplicates(string S) {
stack<char> st;
int len = S.length();
for(int i = 0; i < len; i++)
{
if(st.empty()||S[i] !=st.top())
{
st.push(S[i]);
}
else
{
st.pop();
}
}
string str = "";
while(!st.empty()){
str += st.top();
st.pop();
}
//这里可以直接用reverse(str.begin(), str.end()); 更方便而且内存消耗更小
string str2 = "";
for(int i = str.length() - 1; i >= 0; i--){
str2 += str[i];
}
return str2;
}
};
官方题解中提到,C++的 std::string 类本身就提供了类似「入栈」和「出栈」的接口,所以这里可以不用stack来模拟,学到了!
class Solution {
public:
string removeDuplicates(string S) {
string stk;
for (char ch : S) {
if (!stk.empty() && stk.back() == ch) {
stk.pop_back();
} else {
stk.push_back(ch);
}
}
return stk;
}
};
2021/3/10 224. 基本计算器(栈)
看到题目首先想到的是数据结构中学到的用两个栈来模拟计算四则运算+括号的表达式,但是题目中只有加减没有乘除运算,所以仅用一个符号栈就可以求得最终的值(题解妙蛙)
class Solution {
public:
int calculate(string s) {
stack<int> st;
st.push(1);
int sign = 1;
long ans = 0;
int len = s.length(), i = 0;
while(i < len){
if(s[i] == ' '){
i++;
}
else if(s[i] == '+'){
sign = st.top();
i++;
}
else if(s[i] == '-'){
sign = -st.top();
i++;
}
else if(s[i] == '('){
st.push(sign);
i++;
}
else if(s[i] == ')'){
st.pop();
i++;
}
else{
long num = 0;
while(i < len && s[i] >= '0' && s[i] <= '9'){
num = num * 10 + s[i] - '0';
i++;
}
ans += sign * num;
}
}
return ans;
}
};
有点坑的是num = num * 10 + s[i] - ‘0’,如果num开的是int就会溢出报错,这里要开long;但是如果改成+ (s[i] - ‘0’) 就可以通过了
2021/3/11 227. 基本计算器 II(还是栈)
今天的题还是计算器,但是与昨天的不同之处在于表达式中没有括号而且加上了乘除运算。
同样用栈来模拟,一开始想到是数字栈+符号栈,空格略过,符号放入符号栈(加减乘除分别用1234代替),数字在放入数字栈时判断一下前面的符号是什么,是加减直接push,乘除就要与前一个数做运算再push,此时乘除要pop;这样遍历一遍后还要将数字栈和符号栈中元素的顺序反转,然后再计算,有点麻烦。
更简单一点的做法是当前元素为数字时,判断前面的符号,加号就直接push,减号就取负push,乘除与前面相同,不需要符号栈了,而且计算最后结果的时候直接把数字栈中的所有数字相加即可。
class Solution {
public:
int calculate(string s) {
stack<int> st1;
int len = s.length();
int flag = 1; //1:+ 2:- 3:* 4:/
int i = 0;
while(i < len){
if(s[i] == ' '){
i++;
}
else if(s[i] == '+'){
flag = 1;
i++;
}
else if(s[i] == '-'){
flag = 2;
i++;
}
else if(s[i] == '*'){
flag = 3;
i++;
}
else if(s[i] == '/'){
flag = 4;
i++;
}
else{
int num = 0;
while(i < len && s[i] >= '0' && s[i] <= '9'){
num = num * 10 + int(s[i] - '0');
i++;
}
if(flag == 3){
long res = num * st1.top();
st1.pop();
st1.push(res);
}
else if(flag == 4){
long res = st1.top() / num;
st1.pop();
st1.push(res);
}
else{
if(flag == 1){
st1.push(num);
}
else {
st1.push(-num);
}
}
}
}
int ans = 0;
while(!st1.empty()){
ans += st1.top();
st1.pop();
}
return ans;
}
};
2021/3/12 331. 验证二叉树的前序序列化
我们可以定义一个概念,叫做槽位。一个槽位可以被看作「当前二叉树中正在等待被节点填充」的那些位置。
二叉树的建立也伴随着槽位数量的变化。每当遇到一个节点时:
如果遇到了空节点,则要消耗一个槽位(flag–);
如果遇到了非空节点(包括数字和#标记),则除了消耗一个槽位外,还要再补充两个槽位(flag++)。
class Solution {
public:
bool isValidSerialization(string preorder) {
int len = preorder.length();
int flag = 1;
int i = 0;
while(i < len){
if(flag == 0) return false;
if(preorder[i] == ','){
i++;
}
else if(preorder[i] == '#'){
i++;
flag--;
}
else{
while(i < len && preorder[i] != ','){
i++;
}
flag++;
}
}
if(flag == 0) return true;
else return false;
}
};
2021/3/13 705. 设计哈希集合
再看再看!!!!!!!!!!!!
class MyHashSet {
private:
vector<list<int>> data;
static const int base = 769;
static int hash(int key) {
return key % base;
}
public:
/** Initialize your data structure here. */
MyHashSet(): data(base) {}
void add(int key) {
int h = hash(key);
for (auto it = data[h].begin(); it != data[h].end(); it++) {
if ((*it) == key) {
return;
}
}
data[h].push_back(key);
}
void remove(int key) {
int h = hash(key);
for (auto it = data[h].begin(); it != data[h].end(); it++) {
if ((*it) == key) {
data[h].erase(it);
return;
}
}
}
/** Returns true if this set contains the specified element */
bool contains(int key) {
int h = hash(key);
for (auto it = data[h].begin(); it != data[h].end(); it++) {
if ((*it) == key) {
return true;
}
}
return false;
}
};
/**
* Your MyHashSet object will be instantiated and called as such:
* MyHashSet* obj = new MyHashSet();
* obj->add(key);
* obj->remove(key);
* bool param_3 = obj->contains(key);
*/