栈是一种数据结构,它是一种特殊的线性表。
栈具有 先进后出(LIFO)的特性 ,也就是最后进入栈的元素最先出栈,而最先进入栈的元素最后出栈。
栈通常有两个基本操作:压栈(push)和出栈(pop)。
压栈是将元素加入栈顶,而出栈是将栈顶元素移除。
栈可以用来进行函数调用的处理、表达式求值、以及其他需要后进先出特性的算法和数据结构。
栈通常用于实现递归算法
、表达式求值
、以及其他需要临时存储临时数据
的场景。
举个例子:
假设我们有一个整数栈,我们可以使用栈来模拟浏览器的“后退”功能。
每当用户访问一个新的网页时,我们将该网页的信息入栈。
当用户想要返回上一页时,我们可以从栈中弹出最近访问的网页信息,实现类似后退功能的效果。
栈(Stack)是一种线性数据结构,只允许在一端进行插入和删除操作。栈的典型应用场景是函数调用栈、表达式求值、括号匹配等。
栈的操作主要包括以下几种:
Push(S, e)
这将使得e成为新的栈顶元素。value = Pop(S)
这将删除栈顶元素,并将它的值赋给变量value
。剩余的元素会向上移动,新的栈顶元素变为原来栈顶元素的下一个元素。top_element = GetTop(S)
这些操作都是基于栈的后进先出(LIFO)原则进行的,即最后进入栈的元素最先被移出。
以下是一个简单的栈的实现示例,使用JavaScript语言实现:
class Stack {
constructor() {
this.items = [];
}
push(item) {
this.items.push(item);
}
pop() {
return this.items.pop();
}
top() {
return this.items[this.items.length - 1];
}
isEmpty() {
return this.items.length === 0;
}
}
// 使用示例:
const stack = new Stack();
stack.push(1);
stack.push(2);
stack.push(3);
console.log(stack.pop()); // 输出3
console.log(stack.top()); // 输出2
console.log(stack.isEmpty()); // 输出false
在上面的示例中,我们定义了一个Stack类,包含了常用的栈操作方法:
我们可以通过创建一个Stack的实例来使用这些方法,对栈进行添加、删除、获取栈顶元素和判断是否为空等操作。
更多详细内容,请微信搜索“前端爱好者
“, 戳我 查看 。
leetcode地址:https://leetcode.cn/problems/valid-parentheses/
给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
示例 1:
输入:s = "()"
输出:true
示例 2:
输入:s = "()[]{}"
输出:true
示例 3:
输入:s = "(]"
输出:false
提示:
1 <= s.length <= 104
s 仅由括号 '()[]{}' 组成
实现代码
/**
* @param {string} s
* @return {boolean}
*/
var isValid = function (s) {
// 新建一个数组(创建一个栈)
var stack = []
// 循环数组
for (let i = 0; i < s.length; i++) {
// 记录当前字符
const start = s[i]
// 如果当前字符等于小括号或者大括号或者中括号的左半边,则入栈
if (s[i] == '(' || s[i] == '{' || s[i] == '[') {
stack.push(s[i])
} else {
// 取出栈内最后一个元素
const end = stack[stack.length - 1]
// 如果当前字符等于小括号或者大括号或者中括号的有半边,则出栈
if (start == ')' && end == '(' || start == '}' && end == '{' || start == ']' && end == '[') {
stack.pop();
} else {
return false
}
}
}
return stack.length == 0
};
leetcode地址:https://leetcode.cn/problems/remove-all-adjacent-duplicates-in-string/
给出由小写字母组成的字符串 ‘S’,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
示例:
输入:"abbaca"
输出:"ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。
提示:
1 <= S.length <= 20000
S 仅由小写英文字母组成。
实现代码
/**
* @param {string} s
* @return {string}
*/
var removeDuplicates = function (s) {
// 新建一个栈,空栈
let stack = []
//循环字符串
for (value of s) {
let prev = stack.pop() // 删掉头部元素
// 当前删除元素不等于当前循环元素,则入栈,并且当前循环元素也入栈
// 如果二者相等,则没有入栈,直接抛弃掉了
if (prev != value) {
stack.push(prev)
stack.push(value)
}
}
return stack.join('')
};
给你一个字符串 path ,表示指向某一文件或目录的 Unix 风格 绝对路径 (以 ‘/’ 开头),请你将其转化为更加简洁的规范路径。
在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (…) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。任意多个连续的斜杠(即,‘//’)都被视为单个斜杠 ‘/’ 。 对于此问题,任何其他格式的点(例如,‘…’)均被视为文件/目录名称。
请注意,返回的 规范路径 必须遵循下述格式:
返回简化后得到的 规范路径 。
示例 1:
输入:path = "/home/"
输出:"/home"
解释:注意,最后一个目录名后面没有斜杠。
示例 2:
输入:path = "/../"
输出:"/"
解释:从根目录向上一级是不可行的,因为根目录是你可以到达的最高级。
示例 3:
输入:path = "/home//foo/"
输出:"/home/foo"
解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。
示例 4:
输入:path = "/a/./b/../../c/"
输出:"/c"
提示:
1 <= path.length <= 3000
path 由英文字母,数字,'.','/' 或 '_' 组成。
path 是一个有效的 Unix 风格绝对路径。
实现源码
/**
* @param {string} path
* @return {string}
*/
var simplifyPath = function (path) {
// 新建一个栈,空栈
let stack = []
let str = ''; // 返回的字符
// 拆分数组
let arr = path.split('/')
// 循环拆分的数组
arr.forEach(item => {
// item存在并且等于'..',则出栈
if (item && item == '..') {
stack.pop()
} else if (item && item != '.') {
// item存在并且不等于'.',则进栈
stack.push(item)
}
})
// 判断数组、栈是否有值,如果有值,则需要join一下,最后前面拼接字符串'//
arr.length ? str = '/' + stack.join('/') : str = '/'
// 返回字符串
return str
};