每周一练 之 数据结构与算法(Stack)
最近公司内部在开始做前端技术的技术分享,每周一个主题的 每周一练,以基础知识为主,感觉挺棒的,跟着团队的大佬们学习和复习一些知识,新人也可以多学习一些知识,也把团队内部学习氛围营造起来。
我接下来会开始把每周一练的题目和知识整理一下,便于思考和巩固,就像今天这篇开始。
学习的道路,很漫长,要坚持,希望大家都能掌握自己喜欢的技术,和自己需要的技术。
本周练习内容:数据结构与算法 —— Stack
这些都是数据结构与算法,一部分方法是团队其他成员实现的,一部分我自己做的,有什么其他实现方法或错误,欢迎各位大佬指点,感谢。
一、栈有什么特点,生活中有什么例子?
- 栈( stack )又称堆栈,是一种后进先出的有序集合,其中一端为栈顶,另一端为栈底,添加元素(称为压栈/入栈或进栈)时,将新元素压入栈顶,删除元素(称为出栈或退栈)时,将栈底元素删除并返回被删除元素。
- 特点:先进后出,后进先出。
- 例子:一叠书、一叠盘子。
二、实现一个栈,并实现下面方法
push(element):添加一个新元素到栈顶。pop():移除栈顶的元素,同时返回被移除的元素。peek():返回栈顶的元素,不对栈做任何修改 (这个方法不会移除栈顶的元素,仅仅返回它)。isEmpty():如果栈没有任何元素就返回true,否则返回false。clear():移除栈里面的所有元素。size():返回栈里的元素个数。这个方法与数组的length属性类似。
方法1:ES6实现
class Stack {
constructor (){
this.items = []
}
push( element ){
this.items.push(element)
}
pop(){
return this.items.pop()
}
peek(){
return this.items[this.items.length - 1]
}
isEmpty(){
return this.items.length === 0
}
clear(){
this.items = []
}
size(){
return this.items.length
}
}
上面实现的方式虽然简单,但是内部 items 属性是公共的,为了满足面向对象变成私有性的原则,我们应该让 items 作为私有属性,因此我们可以使用 ES6 中 Symbol 或 WeakMap 来实现:
方法2:使用 ES6 的 Symbol 基本数据类型实现
知识点复习:ES6 中的 Symbol 介绍
const _items = Symbol()
class Stack {
constructor (){
this[_items] = []
}
push (element){
this[_items].push(element)
}
// 剩下方法和第一种实现的差不多,这里省略
// 只要把前面方法中的 this.items 更改为 this[_items]
}
方法3:使用 ES6 的 WeakMap 实现
知识点复习:ES6 中的 WeakMap 介绍
const items = new WeakMap()
class Stack {
constructor (){
items.set(this, [])
}
push (element){
let item = items.get(this)
item.push(element)
}
// 剩下方法和第一种实现的差不多,这里省略
// 只要把前面方法中的获取 this.items 的方式,更改为 items.get(this) 获取
}
三、编写一个函数,实现十进制转二进制
题目意思很简单,就是十进制转二进制,但是在实际工作开发中,我们更愿意实现的是任意进制转任意进制,不过呢,我们还是以解决问题为首要目标呀。
当然,业务需求可以直接使用 toString(2) 方法,但是为了练习,咱还是不这么用咯。
方法1:使用前面定义的 Stack 类
这里使用前面题目中定义的 Stack 类。
/**
* 十进制转换为二进制
* @param {Number} bit
*/
function bitset (bit){
if(bit == 0) return '0'
if(!/^[0-9]+.?[0-9]*$/.test(bit)){
return new Error('请输入正确的数值!')
}
let stack = new Stack(), result = ''
while (bit > 0){
stack.push(bit % 2)
bit = Math.floor(bit / 2)
}
while (!stack.isEmpty()){
result += stack.pop().toString()
}
return result
}
方法2:简单实现
下面这个方法,其实不太好,因为没有怎么用到这次要练习的栈方法,哈哈。
/**
* 十进制转换为二进制
* @param {Number} bit
*/
function bitset (bit){
if(bit == 0) return '0'
if(!/^[0-9]+.?[0-9]*$/.test(bit)){
return new Error('请输入正确的数值!')
}
let arr = []
while(bit > 0){
arr.push(bit % 2)
bit = Math.floor(bit / 2)
}
return arr.reverse().join('')
}
另外可以参考:wikiHow - 从十进制转换为二进制。
四、编写一个函数,实现检验圆括号顺序的有效性
主要目的就是:该函数接收一个圆括号字符串,判断里面的括号顺序是否有效,如果有效则返回 true 反之 false。
如:
(->false()->true(()->false())->false())->false(((()()))())->true
这个题目实现的主要方法是:遍历字符串,先排除错误情况,然后将 ( 入栈保存,将 ) 入栈匹配前一个元素是否是 ( ,如果是,则 pop() 前一个元素 (,如果不是,则 push() 这个 ) 入栈,最终查看栈是否为空,若是则检验成功,否则失败。
方法1:使用前面定义的 Stack 类
这里使用前面题目中定义的 Stack 类。
/**
* 检验圆括号顺序的有效性
* @param {String} str
*/
function validParentheses (str){
if(!str || str.length === 0 || str[0] === ')') return false
let stack = new Stack()
str.split('').forEach(char => {
let status = stack.peek() === '(' && char === ')'
status ? stack.pop() : stack.push(char)
})
return stack.isEmpty()
}
方法2:出入栈操作
/**
* 检验圆括号顺序的有效性
* @param {String} str
*/
function validParentheses (str){
if(!str || str.length === 0 || str[0] === ')') return false
let arr = []
for(let i = 0; i < str.length ; i++){
str[i] === '(' ? arr.push(str[i]) : arr.pop()
}
return arr.length === 0
}
五、改造题二,添加一个 min 函数来获得栈中最小元素
| 步骤 | 数据栈 | 辅助栈 | 最小值 |
|---|---|---|---|
| 1.push 3 | 3 | 0 | 3 |
| 2.push 4 | 3, 4 | 0, 0 | 3 |
| 3.push 2 | 3, 4, 2 | 0, 0, 2 | 2 |
| 4.push 1 | 3, 4, 2 ,1 | 0, 0, 2, 3 | 1 |
| 5.pop | 3, 4, 2 | 0, 0, 2 | 2 |
| 6.pop | 3, 4 | 0, 0 | 3 |
| 7.push | 3, 4 ,0 | 0, 0, 2 | 0 |
使用示例如下:
let stack = new Stack();
stack.push(3);
console.log('After push 3, Min item is', stack.min());
stack.push(4);
console.log('After push 4, Min item is', stack.min());
stack.push(2);
console.log('After push 2, Min item is', stack.min());
stack.push(1);
console.log('After push 1, Min item is', stack.min());
stack.pop();
console.log('After pop, Min item is', stack.min());
stack.pop();
console.log('After pop, Min item is', stack.min());
stack.push(0);
console.log('After push 0, Min item is', stack.min());
提示:利用辅助栈(Web 端可利用数组),每次对栈 push/pop 元素时,也同时更新辅助栈(存储最小元素的位置)
方法1:小操作
class Stack {
constructor() {
this.items = [];
this.minIndexStack = [];
}
push(element) {
this.items.push(element);
let minLen = this.minIndexStack.length;
let minItemIndex = this.minIndexStack[minLen - 1];
if(minLen === 0 || this.items[minItemIndex] > item) {
this.minIndexStack.push(this.items.length - 1);
} else {
this.minIndexStack.push(minItemIndex);
}
}
pop() {
this.minIndexStack.pop();
return this.items.pop();
}
min() {
let len = this.minIndexStack.length;
return (len > 0 && this.items[this.minIndexStack[len - 1]]) || 0;
}
peek() {
return this.items[this.items.length - 1];
}
// 省略其它方法
}
方法2:与方法1中push实现的差异
class Stack {
constructor (){
this.items = [] // 数据栈
this.arr = [] // 辅助栈
}
push( element ){
this.items.push(element)
let min = Math.min(...this.items)
this.arr.push( min === element ? this.size() - 1 : 0)
}
pop(){
this.arr.pop()
return this.items.pop()
}
peek(){
return this.items[this.items.length - 1]
}
isEmpty(){
return this.items.length === 1
}
clear(){
this.items = []
}
size(){
return this.items.length
}
min (){
let last = this.arr[this.arr.length - 1]
return this.items[last]
}
}
下周预告
下周将练习队列(Queue) 的题目,开始翻起算法书籍学习咯。
每周一练 之 数据结构与算法(Stack)的更多相关文章
- 每周一练 之 数据结构与算法(LinkedList)
这是第三周的练习题,原本应该先发第二周的,因为周末的时候,我的母亲大人来看望她的宝贝儿子,哈哈,我得带她看看厦门这座美丽的城市呀. 这两天我抓紧整理下第二周的题目和答案,下面我把之前的也列出来: 1. ...
- 每周一练 之 数据结构与算法(Set)
这是第四周的练习题,五一放假结束,该收拾好状态啦. 下面是之前分享的链接: 1.每周一练 之 数据结构与算法(Stack) 2.每周一练 之 数据结构与算法(LinkedList) 2.每周一练 之 ...
- 每周一练 之 数据结构与算法(Queue)
这是第二周的练习题,这里补充下咯,五一节马上就要到了,自己的计划先安排上了,开发一个有趣的玩意儿. 下面是之前分享的链接: 1.每周一练 之 数据结构与算法(Stack) 2.每周一练 之 数据结构与 ...
- 每周一练 之 数据结构与算法(Tree)
这是第六周的练习题,最近加班比较多,上周主要完成一篇 GraphQL入门教程 ,有兴趣的小伙伴可以看下哈. 下面是之前分享的链接: 1.每周一练 之 数据结构与算法(Stack) 2.每周一练 之 数 ...
- 每周一练 之 数据结构与算法(Dictionary 和 HashTable)
这是第五周的练习题,上周忘记发啦,这周是复习 Dictionary 和 HashTable. 下面是之前分享的链接: 1.每周一练 之 数据结构与算法(Stack) 2.每周一练 之 数据结构与算法( ...
- 【算法】273-每周一练 之 数据结构与算法(Tree)
这是第六周的练习题,最近加班比较多. 下面是之前分享的链接: [算法]200-每周一练 之 数据结构与算法(Stack) [算法]213-每周一练 之 数据结构与算法(LinkedList) [算法] ...
- 【算法】272-每周一练 之 数据结构与算法(Dictionary 和 HashTable)
这是第五周的练习题,上周忘记发啦,这周是复习 Dictionary 和 HashTable. 下面是之前分享的链接: [算法]200-每周一练 之 数据结构与算法(Stack) [算法]213-每周一 ...
- 数据结构与算法-stack
栈的本质是一种线性表,特殊的一种线性表 基本概念 概念 栈是一种特殊的线性表 栈仅能在线性表的一端进行操作 栈顶(Top):允许操作的一端 栈底(Bottom):不允许操作的一端 stack是一种线性 ...
- 【Java数据结构学习笔记之二】Java数据结构与算法之栈(Stack)实现
本篇是java数据结构与算法的第2篇,从本篇开始我们将来了解栈的设计与实现,以下是本篇的相关知识点: 栈的抽象数据类型 顺序栈的设计与实现 链式栈的设计与实现 栈的应用 栈的抽象数据类型 栈是 ...
随机推荐
- xilinx FPGA全局时钟资源的使用
1.什么是xilinx fpga全局时钟资源 时钟对于一个系统的作用不言而喻,就像人体的心脏一样,如果系统时钟的抖动.延迟.偏移过大,会导致系统的工作频率降低,严重时甚至会导致系统的时序错乱,实现不了 ...
- DAGScheduler stage 划分算法
DAGScheduler stage 划分算法 stage划分算法很重要,对于spark开发人员来说,必须对stage划分算法很清晰,知道自己编写的spark Application被划分成了几个jo ...
- PHP文件上传和下载
第 1 章 文件上传 1.1 客户端上传设置 在 B/S 程序中文件上传已经成为一个常用功能.其目的是客户可以通过浏览器 (Browser) 将文件上传到服务器(Server)上的指定目录. 网络上常 ...
- Spring 5 响应式编程
要点 Reactor 是一个运行在 Java8 之上的响应式流框架,它提供了一组响应式风格的 API 除了个别 API 上的区别,它的原理跟 RxJava 很相似 它是第四代响应式框架,支持操作融合, ...
- oracle插入,更新,删除数据
插入,更新,删除数据 oracle提供了功能丰富的数据库管理语句 包括有效的向数据库中插入数据的insert语句 更新数据的update语句 以及当数据不再使用时删除数据的delete语句 更改数据之 ...
- mysql--时区问题(时间差8个小时?修改Mysql 时区)
发现评论时间比本地时间晚8小时,原因:mysql默认时区选择了CST 解决办法: Ubuntu系统环境下: 1.检查mysql系统时区 进入mysql:mysql -u root -p mysql&g ...
- VS Code 中文社区正式成立啦!VS Code Day 圆满落幕!
背景简介 Visual Studio Code 是一款现代化轻量级代码编辑器,它免费.开源.跨平台.功能强大.本次 VS Code Day 是广大 VS Code 爱好者一起学习与交流的盛会,让我们对 ...
- CSP2019,RP+=150。
csp2019游记 第一题水死了,2分钟过! 第二题被卡住了,才得了30分. 第三题背包DP,可惜了,出了考场才知道... 第四题骗到20分,也算心满意足了.. 150,省二左右,辣鸡... 反正就是 ...
- JAVA合并多个word文档根据文章标题生成目录
此产品版本是免费版的,我也是在用免费,除了只能单次识别25张一下的word和生成pdf有限制,其他的功能都和正式版差不多. 如果你几十个文档,每个文档几页,输出出来超过25页,那没关系,依然可以使用. ...
- QQ登录功能之如何获取用于本地测试的APPID
本文主要说明一下开发者如何在QQ互联创建测试应用,从而分配给我们一套APP ID和APP KEY,在我们平时学习的时候使用. 一.QQ互联注册开发者 要想使用QQ登陆的功能,首先你必须是腾讯开发者.腾 ...