一、化栈为队列
LeetCode03.04题:化栈为队列
解题思路
设置两个栈s1和s2来模拟一个队列,s2负责入队,s1负责出队;
当s1为空时,如果s2不为空,则将s2中的内容出栈,再入栈到s1;
代码实现
// 实现一个栈
class Stack {
constructor() {
this.stack = []
}
push(x) {
this.stack.push(x);
}
pop() {
if(this.empty()) return;
let top = this.top();
this.stack.pop()
return top;
}
top() {
return this.stack[this.size()-1]
}
empty() {
return this.stack.length == 0;
}
size() {
return this.stack.length;
}
}
// 两个栈实现一个队列
/**
* Initialize your data structure here.
*/
var MyQueue = function() {
// 创建两个栈
this.s1 = new Stack();
this.s2 = new Stack();
};
// 当s1为空时,将s2内容压入s1中
MyQueue.prototype.transfer = function() {
if(!this.s1.empty()) return;
while(!this.s2.empty()) {
this.s1.push(this.s2.pop())
}
}
/**
* Push element x to the back of queue.
* @param {number} x
* @return {void}
* @description 入队时将数据放入S2中
*/
MyQueue.prototype.push = function(x) {
this.s2.push(x);
};
/**
* Removes the element from in front of queue and returns that element.
* @return {number}
* @description 出队时判断s1中是否有值,若有,直接将s1栈顶出去;若无,则将s2中的数据全都出栈到s1再将s1栈顶出去。
*/
MyQueue.prototype.pop = function() {
this.transfer();
let top = this.s1.top();
this.s1.pop();
return top;
};
/**
* Get the front element.
* @return {number}
* @description 队头即s1栈顶,也需要对s1进行判断
*/
MyQueue.prototype.peek = function() {
this.transfer();
return this.s1.top();
};
/**
* Returns whether the queue is empty.
* @return {boolean}
* @description s1和s2都为空时队列为空
*/
MyQueue.prototype.empty = function() {
return this.s1.empty() && this.s2.empty();
};
/**
* Your MyQueue object will be instantiated and called as such:
* var obj = new MyQueue()
* obj.push(x)
* var param_2 = obj.pop()
* var param_3 = obj.peek()
* var param_4 = obj.empty()
*/
二、入栈出栈
LeetCode03.04题:棒球比赛
解题思路
- 当遇到数字:进栈;
- 当遇到加号:取栈顶值top,将栈顶出栈,再取栈顶值与top相加,把top放回栈中,再将相加的值放入栈中;
- 当遇到D:将栈顶值乘2,并将所得的值放入栈中;
- 当遇到C:将栈顶值出栈。
最后当栈不为空时,遍历整个栈,将栈顶值出栈并相加,返回相加后的值。
代码实现
// 实现一个栈
class Stack {
constructor() {
this.stack = []
}
push(x) {
this.stack.push(x);
}
pop() {
if(this.empty()) return;
let top = this.top();
this.stack.pop()
return top;
}
top() {
return this.stack[this.size()-1]
}
empty() {
return this.stack.length == 0;
}
size() {
return this.stack.length;
}
}
/**
* @param {string[]} ops
* @return {number}
*/
var calPoints = function(ops) {
let stack = new Stack();
let sumScore = 0;
for(let i = 0; i < ops.length; i++) {
if(ops[i] == '+') {
let sum = 0;
let top1 = 0;
if(!stack.empty()) {
top1 = stack.pop();
sum += top1;
console.log(stack)
}
if(!stack.empty()) {
sum += stack.top();;
}
stack.push(top1);
stack.push(sum);
} else if(ops[i] == 'D') {
let score = 0;
if(!stack.empty()) {
score = stack.top();
}
stack.push(score * 2);
} else if(ops[i] == 'C') {
if(!stack.empty()) {
stack.pop();
}
} else {
stack.push(ops[i] * 1)
}
}
while(!stack.empty()) {
sumScore += stack.pop();
}
return sumScore;
};
三、入栈出栈
LeetCode844题:比较含退格的字符串
解题思路
设置两个栈,当遇到#则出栈,其他字符入栈;
当两个字符串都入栈后,比较两个栈的长度是否相等,若不相等,则两个字符串不可能相等,返回false;
遍历两个栈,比较两个栈的栈顶,如果栈顶不相等,则两个字符串不可能相等,返回false;直到栈为空时,战斗都相等则返回true。
代码实现
// 实现一个栈
class Stack {
constructor() {
this.stack = []
}
push(x) {
this.stack.push(x);
}
pop() {
if(this.empty()) return;
let top = this.top();
this.stack.pop()
return top;
}
top() {
return this.stack[this.size()-1]
}
empty() {
return this.stack.length == 0;
}
size() {
return this.stack.length;
}
}
/**
* @param {string} s
* @param {string} t
* @return {boolean}
*/
var backspaceCompare = function(s, t) {
let stack1 = new Stack();
let stack2 = new Stack();
transfer(stack1, s);
transfer(stack2, t);
// 判断两个栈的长度是否相同,若不相同则不可能相等
if(stack1.size() != stack2.size())return false;
while(!stack1.empty()) {
if(stack1.top() != stack2.top()) return false;
stack1.pop();
stack2.pop();
}
return true;
};
// 遍历判断是否为#,若是则出栈,否则进栈
var transfer = function(stack, str) {
for(var i = 0; i < str.length; i++) {
if(str[i] == '#') {
// !stack.empty() && stack.pop();
if(!stack.empty()) {
stack.pop()
}
} else {
stack.push(str[i]);
}
}
}
四、验证栈序列
LeetCode946题:验证栈序列
解题思路
pushed中的元素一直入栈,直到有元素和popped中未检测的首个元素相等,出栈,则检测通过,进行下个元素的检测。
当pushed中所有元素都进栈了,然而栈顶不等于监测值时,说明popped的操作序列不对了。
代码实现
class Stack {
constructor() {
this.stack = []
}
push(x) {
this.stack.push(x);
}
pop() {
if(this.empty()) return;
let top = this.top();
this.stack.pop()
return top;
}
top() {
return this.stack[this.size()-1]
}
empty() {
return this.stack.length == 0;
}
size() {
return this.stack.length;
}
}
/**
* @param {number[]} pushed
* @param {number[]} popped
* @return {boolean}
*/
var validateStackSequences = function(pushed, popped) {
let stack = new Stack();
//
let j = 0;
// 遍历poped
for(let i = 0; i < popped.length; i++) {
// 当pushed中有值,且stack为空或栈顶不等于poped[i]时
while(j < pushed.length && (stack.empty() || stack.top() != popped[i])) {
// 将pushed[i]入栈
stack.push(pushed[j]);
j++;
}
// 当因为j>=pushed.length跳出来时,如果栈顶不等于poped[i],那么可以判断poped的操作序列是不对的
if(stack.top() != popped[i]) return false;
stack.pop();
}
return true;
};
五、有效的括号
LeetCode946题:有效的括号
解题思路
当字符为左括号时入栈;
为右括号时检测栈不为空且栈顶为对应的左括号时出栈,否则无效,返回false。
代码实现
class Stack {
constructor() {
this.stack = []
}
push(x) {
this.stack.push(x);
}
pop() {
if(this.empty()) return;
let top = this.top();
this.stack.pop()
return top;
}
top() {
return this.stack[this.size()-1]
}
empty() {
return this.stack.length == 0;
}
size() {
return this.stack.length;
}
}
/**
* @param {string} s
* @return {boolean}
*/
var isValid = function(s) {
let stack = new Stack();
for(let i = 0; i< s.length; i++) {
switch(s[i]) {
case '(':
case '[':
case '{': stack.push(s[i]); break;
case ')': if(stack.empty() || stack.top() != '(') return false;
stack.pop();
break;
case ']': if(stack.empty() || stack.top() != '[') return false;
stack.pop();
break;
case '}': if(stack.empty() || stack.top() != '{') return false;
stack.pop();
break;
}
}
return stack.empty();
};
六、删除最外层的括号
LeetCode1021题:删除最外层的括号
解题思路
设置left表示最外层左括号位置;设置cnt,当遇到左括号++,右括号--。
当cnt为0时,证明左右括号对等,则当前所在位置便是最外层右括号的位置,所以使用slice(最外层左括号位置, 最外层右括号位置)提取出删除最外层括号的字符串。
将left指向最外层右括号的后一位,继续检测。
代码实现
/**
* @param {string} s
* @return {string}
*/
var removeOuterParentheses = function(s) {
let left = 0;
let cnt = 0;
let str = '';
for(let i = 0; i < s.length; i++) {
if(s[i] == '(') {
cnt ++;
} else {
cnt --;
}
// 当左右括号配对完,证明第i个字符就是最外层的右括号
if(cnt != 0) {
continue;
}
// 截取除了最外层左右括号的字符串
str += s.slice(left + 1, i);
// 将left移到i右边一位继续检测
left = i + 1;
}
return str;
};
七、移除无效的括号
LeetCode1249题:移除无效的括号
解题思路
1.先从左到右遍历删去无效右括号:
- 当遇到左括号,ctn+1;
- 左括号和其他字符都放进str中;
- 当遇到右括号,判断ctn是否为0,若不为0,则将ctn--,并将当前右括号放进str字符串中,若是0则表示前面字符串中没有与当前右括号匹配的左括号,所以不将当前右括号放进字符串,退出当前循环。
2.再从右到左遍历删去无效左括号:与步骤1中思路一致。
3.由于2中得到的字符串是反转的,所以需要将字符串反转回来。
代码实现
/**
* @param {string} s
* @return {string}
*/
var minRemoveToMakeValid = function(s) {
let ctn = 0; // 判断左右括号是否对等
let str = '';
let ans = '';
// 从左到右遍历字符串去除无效右括号
for(let i = 0; i < s.length; i++) {
if(s[i] != ')') { //当不为右括号的时候
ctn += (s[i] == '(');
str += s[i]; // 将当前字符加入str字符串中
} else {
// 当ctn为0时证明前面没有匹配的左括号,所以不做任何操作
if(ctn == 0) continue;
// 当ctn不为0时,ctn减1,并将当前右括号加入str字符串中
ctn --;
str += s[i];
}
}
// 从右到左遍历字符串去除无效左括号
ctn = 0;
for(let i = str.length - 1; i >= 0; i --) {
if(str[i] != '(') {
ctn += (str[i] == ')');
ans += str[i];
} else {
if(ctn == 0) continue;
ctn --;
ans += str[i];
}
}
// 由于是从右到左遍历,所以需要将字符串反转过来
ans = ans.split('').reverse().join('');
console.log(ans)
return ans;
};
八、二叉树的后序遍历
LeetCode145题:二叉树的后序遍历
后序遍历:左右根
前序遍历:根左右
中序遍历:左根右
解题思路一
采用递归的写法,层层递进,将根节点左边的所有层级处理完,再处理根节点右边的所有层级,最后再处理根节点。
代码实现
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
var postorder = function(root, ans) {
if(root == null) return;
postorder(root.left, ans);
postorder(root.right, ans);
ans.push(root.val);
}
/**
* @param {TreeNode} root
* @return {number[]}
*/
var postorderTraversal = function(root) {
let ans = [];
postorder(root, ans);
return ans;
};