整理一下刷题过程中的思路,在这里进行一下总结与分享。
github地址:https://github.com/lvjian0706/Leetcode-solutions
github项目是刚刚新建的,陆续会将整理的代码以及思路上传上去,代码是基于C++与python的。同时会将基础的排序算法等也一并进行整理上传。
给定一个二叉树,返回它的中序 遍历。
示例:
输入: [1,null,2,3]
1
2
/
3
输出: [1,3,2]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
/*
回溯方法
*/
void DFS(TreeNode* root, vector<int> &ans){
if(!root) return;
DFS(root->left, ans);
ans.push_back(root->val);
DFS(root->right, ans);
}
/*
中序遍历,可以使用回溯思想
*/
vector<int> inorderTraversal(TreeNode* root) {
vector<int> ans;
DFS(root, ans);
return ans;
}
};
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
/*
迭代方法:(使用vector和stack共同解决)
1. 中序遍历,访问左孩子节点存到栈中;
2. 访问结束后,pop()出栈顶元素,存到结果数组中;
3. 将root定义为栈顶元素的右孩子,遍历右子树;
*/
vector<int> inorderTraversal(TreeNode* root) {
vector<int> ans;
stack<TreeNode*> inorder_tree;
while(root || !inorder_tree.empty()){
while(root){
inorder_tree.push(root);
root = root->left;
}
TreeNode* temp = inorder_tree.top();
inorder_tree.pop();
ans.push_back(temp->val);
root = temp->right;
}
return ans;
}
};
根据 逆波兰表示法,求表达式的值。
有效的运算符包括 +, -, *, / 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
说明:
整数除法只保留整数部分。
给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。
示例 1:
输入: [“2”, “1”, “+”, “3”, “"]
输出: 9
解释: 该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
示例 2:
输入: [“4”, “13”, “5”, “/”, “+”]
输出: 6
解释: 该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
示例 3:
输入: [“10”, “6”, “9”, “3”, “+”, “-11”, "”, “/”, “*”, “17”, “+”, “5”, “+”]
输出: 22
解释:
该算式转化为常见的中缀算术表达式为:
((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22
逆波兰表达式:
逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。
平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:
去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中。
class Solution {
public:
/*
逆波兰表达式求值:
使用栈来存储每个数字以及当前的计算结果;为了方便定义flag标志位,使用switch语句进行判断;
1. 当字符串长度大于1或字符串的第一个元素大于‘0’小于‘9’时,说明字符串中为数字,将string转为int后入栈;(注意处理2位数以上的数以及负数)
2. 当字符串中存储的是运算符:将栈顶的两个元素取出后进行计算,结果重新入栈;
3. 栈顶元素为最终结果;
*/
int evalRPN(vector<string>& tokens) {
stack<int> nums;
static const int NUMBER = 1;
static const int OPERATOR = 2;
int flag = NUMBER;
for(int i=0; i<tokens.size(); i++){
string mem = tokens[i];
if(mem.size()>1 || (mem[0]>='0' && mem[0]<='9')) flag = NUMBER;
else flag = OPERATOR;
switch(flag){
case NUMBER:{
int j=0, temp=0;
if(mem[0]=='-') j++;
while(mem[j]>='0' && mem[j]<='9'){
temp = temp * 10 + mem[j] - '0';
j++;
}
if(mem[0]=='-') nums.push(0-temp);
else nums.push(temp);
break;
}
case OPERATOR:{
int num1 = nums.top();
nums.pop();
int num2 = nums.top();
nums.pop();
if(mem[0]=='+') nums.push(num2+num1);
else if(mem[0]=='-') nums.push(num2-num1);
else if(mem[0]=='*') nums.push(num2*num1);
else if(mem[0]=='/') nums.push(num2/num1);
break;
}
}
}
return nums.top();
}
};
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。
示例:
输入:
[“MinStack”,“push”,“push”,“push”,“getMin”,“pop”,“top”,“getMin”]
[[],[-2],[0],[-3],[],[],[],[]]
输出:
[null,null,null,null,-3,null,0,-2]
解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.getMin(); --> 返回 -2.
提示:
pop、top 和 getMin 操作总是在 非空栈 上调用。
class MinStack {
public:
/*
设计常数时间内检索到最小元素的栈:
需要定义变量存储最小值,考虑到当最小值弹出后能及时更新最小值,定义了min_stack存储截止到每个位置的最小值;
1. push(),top()操作正常;
2. getMin()操作直接返回min_stack的栈顶元素;
3. push()操作:
3.1 real_stack直接入栈;
3.2 判断x与min_stack的栈顶元素谁小,将最小值入栈;
*/
/** initialize your data structure here. */
MinStack() {
}
void push(int x) {
real_stack.push(x);
if(min_stack.empty()) min_stack.push(x);
else min_stack.push(min(x, min_stack.top()));
}
void pop() {
real_stack.pop();
min_stack.pop();
}
int top() {
return real_stack.top();
}
int getMin() {
return min_stack.top();
}
private:
stack<int> real_stack;
stack<int> min_stack;
};
/**
* Your MinStack object will be instantiated and called as such:
* MinStack* obj = new MinStack();
* obj->push(x);
* obj->pop();
* int param_3 = obj->top();
* int param_4 = obj->getMin();
*/
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。
示例 1:
输入:s = “3[a]2[bc]”
输出:“aaabcbc”
示例 2:
输入:s = “3[a2[c]]”
输出:“accaccacc”
示例 3:
输入:s = “2[abc]3[cd]ef”
输出:“abcabccdcdcdef”
示例 4:
输入:s = “abc3[cd]xyz”
输出:“abccdcdcdxyz”
class Solution {
public:
/*
将字符串s重复n遍返回;
*/
string repeatStr(string s, int n){
string ans = "";
for(int i=0; i<n; i++){
ans.append(s);
}
return ans;
}
/*
给定一个经过编码的字符串(编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。),返回它解码后的字符串:
1. 使用栈来进行计算,建立两个栈分别存储k和encoded_string;
2. 定义三个状态:BEGIN,NUMBER,CHARATOR分别代表起始状态,处理数字k,处理encoded_string;
3. 遍历s,进行处理:
3.1 BEGIN:判断第一个字符为数字还是encoded_string;
3.2 NUMBER:将数字入nums栈;
3.3 CHARATOR:
3.3.1 s[i]!=']'时,将字符直接入dec_str栈;
3.3.2 s[i]==']'时,解码字符串:
3.3.2.1 取出字符串栈中的元素,直到取到'['为止,取出的元素则为需要重复的元素;
3.3.2.2 将取出的字符连成字符串并重复n遍,n为nums栈中的栈顶元素;
3.3.2.3 将新字符串入dec_str栈;
4. dec_str中最后存储着解码后的字符串片段,拼接之后就是最终答案;
*/
string decodeString(string s) {
stack<int> nums;
stack<string> dec_str;
static const int BEGIN = 0;
static const int NUMBER = 1;
static const int CHARATOR = 2;
int flag = BEGIN;
for(int i=0; i<s.size(); i++){
switch(flag){
case BEGIN:{
if(s[i]>='0' && s[i]<='9') flag = NUMBER;
else flag = CHARATOR;
i--;
break;
}
case NUMBER:{
if(s[i]<'0' || s[i]>'9') flag = CHARATOR;
else{
int temp = 0;
while(s[i]>='0' && s[i]<='9'){
temp = temp * 10 + s[i] - '0';
i++;
}
nums.push(temp);
}
i--;
break;
}
case CHARATOR:{
if(s[i]>='0' && s[i]<='9'){
flag = NUMBER;
i--;
}
else if(s[i]!=']'){
string mem;
mem.push_back(s[i]);
dec_str.push(mem);
}
else{
/*
1. 取出字符串栈中的元素,直到取到'['为止,取出的元素则为需要重复的元素;
2. 将取出的字符连成字符串并重复n遍,n为nums栈中的栈顶元素;
3. 将新字符串入dec_str栈;
*/
string temp_str = "";
while(dec_str.top()[0]!='['){
string top_string = dec_str.top();
dec_str.pop();
temp_str.insert(0, top_string);
}
dec_str.pop(); //去掉'['
int times = nums.top();
nums.pop();
string repeat_str = repeatStr(temp_str, times);
dec_str.push(repeat_str);
}
break;
}
}
}
string ans = "";
while(!dec_str.empty()){
string mem_str = dec_str.top();
dec_str.pop();
ans.insert(0, mem_str);
}
return ans;
}
};