01-线性结构-数组-栈结构
线性结构(Linear List)是由n(n>=0)个数据元素(结点) a[0], a[1], a[2], a[3],...,a[n-1]组成的有限序列
数组
通常数组的内存是连续的,所以在知道数组下标的情况下,访问效率是非常高的
可在数组的任意位置插入和删除数据
栈结构
简介
- 是一种受限的线性结构,先进后出
- 仅允许在表的一端进行插入和删除运算,即栈顶;另一端为栈底。
- 必须按照顺序来进出栈
习题练习:
题目
有六个元素6,5,4,3,2,1的顺序进栈,问下列哪一个不是合法的出栈序列?(C )
A. 5 4 3 6 1 2 B. 4 5 3 2 1 6 C. 3 4 6 5 2 1 D. 2 3 4 1 5 6
答案解析:
A:65进栈,5出栈,4进栈出栈,3进栈出栈,6出栈,21进栈,1出栈,2出栈
B:654进栈,4出栈,5出栈,3进栈出栈,2进栈出栈,1进栈出栈,6出栈
D:65432进栈,2出栈,3出栈,4出栈,1进栈出栈,5出栈,6出栈
实现栈结构
// 封装一个栈
class ArrayStack {
// 定义一个数组/链表。用于存储数据
private data: any[] = []
// 实现栈中相关的操作方法
// 1.push方法:将一个元素压入到栈中
push(element: any):void {
this.data.push(element)
}
// 2.pop方法:将栈顶的元素弹出栈(返回出去,并且移除该项)
pop():any {
return this.data.pop()
}
// 3peek方法:看一眼栈顶元素,但是不进行任何操作
peek(): any {
return this.data[this.data.length - 1]
}
// 4.isEmpty:判断栈是否为空
isEmpty(): boolean {
return this.data.length === 0
}
// 5.size:返回栈的数据个数
size(): number {
return this.data.length
}
}
对上述代码进行测试:
// 创建stack实例
const stack1 = new ArrayStack()
stack1.push("aaa")
stack1.push("bbb")
stack1.push("ccc")
console.log(stack1.peek());//ccc
console.log(stack1.pop());//ccc
console.log(stack1.pop());//bbb
console.log(stack1.pop());//aaa
console.log(stack1.isEmpty());//true
console.log(stack1.size());//0
相关应用
十进制转二进制
import ArrayStack from "./02-实现栈结构Stacks(重构)"
function decimalToBinary(decimal: number): string {
// 1.创建一个栈,用于存放余数
const stack = new ArrayStack<number>()
/*
2.使用循环
// while:不确定次数,只知道循环结束跳转
// for:知道循环的次数
*/
while(decimal > 0) {
const result = decimal % 2
stack.push(result)
decimal = Math.floor(decimal / 2)
}
// 3.所有的余数都已经放在stack中,依次取出即可
let binary = ''
while(!stack.isEmpty()) {
binary += stack.pop()
}
return binary
}
console.log(decimalToBinary(35));//100011
console.log(decimalToBinary(100));//1100100
有效的括号
20. 有效的括号 - 力扣(LeetCode)(考察栈)
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
解题:
import ArrayStack from "./02-实现栈结构Stacks(重构)"
function isValid(s:string): boolean {
// 1.创建一个栈结构
const stack = new ArrayStack<string>()
// 2.变量s中的所有括号
for(let i = 0; i < s.length; i++) {
const c = s[i]
switch(c) {
case "(":
stack.push(")")
break
case "{":
stack.push("}")
break
case "[":
stack.push("]")
break
default:
if(c !== stack.pop()) return false
break
}
}
return stack.isEmpty()
}
console.log(isValid("()"));
console.log(isValid("()[]{}["));
02-队列结构-面试题
- 队列(queue)是一种先进先出的线性结构
- 数据元素按照顺序依次进入队列,最先进入的元素最先离开队列
- 类似于现实中的排队场景,比如排队买票,先到的人先离开队列
- 常见的队列结构
实现队列结构
1.定义队列结构接口
interface IQueue<T> {
// 入队方法
enqueue(element: T): void
// 出队方法
dequeue(): T | undefined
// peek 方法
peek(): T | undefined
// 判断是否为空
isEmpty(): boolean
// 元素个数
size(): number
}
export default IQueue
2.实现队列结构
import IQueue from "./IQueue"
class ArrayQueue<T> implements IQueue<T> {
// 内部通过数组或链表保存数据
private data: T[] = []
enqueue(element: T): void {
this.data.push(element)
}
dequeue(): T | undefined {
return this.data.shift()
}
peek(): T | undefined {
return this.data[0]
}
isEmpty(): boolean {
return this.data.length === 0
}
size(): number {
return this.data.length
}
}
export default ArrayQueue
3.测试代码:
import ArrayQueue from "./01-实现队列结构";
const queue = new ArrayQueue<number>()
queue.enqueue(1)
queue.enqueue(2)
queue.enqueue(3)
console.log(queue.dequeue());//1
console.log(queue.dequeue());//2
console.log(queue.size());//1
击鼓传花
要求:一群人围成一圈,获取最后剩下的人位置或名字
import ArrayQueue from "./01-实现队列结构"
function hotPotatao (names:string[],num:number) {
if(names.length === 0) return -1
// 创建队列结构
const queue = new ArrayQueue<string>()
// 2.将所有name入队操作
for (const name of names) {
queue.enqueue(name)
}
// 3.淘汰的规则
while(queue.size()>1){
// 1、2淘汰
for(let i = 1;i<num; i++) {
const name = queue.dequeue()
if(name) queue.enqueue(name)
}
// 3淘汰
queue.dequeue()
}
// return queue.dequeue()
const Leftname = queue.dequeue()!
// 拿到当前名字的索引
return names.indexOf(Leftname)
}
const leftName = hotPotatao(["张三","李四","王五","赵六","钱七"],3)
console.log(leftName);
约瑟夫环
0,1,...,n-1个数字围城一个圈,从数字0开始,每次删除圆圈中第m个数字(删除后从下一个数字计数)。求该圆圈剩下的最后一个数字。
import ArrayQueue from "./01-实现队列结构"
function lastRemaining(n:number,m:number) {
// 输入参数校验
if (n <= 0 || m <= 0) {
throw new Error("参数 n 和 m 必须大于 0");
}
// 1.创建队列
const queue = new ArrayQueue<number>()
// 2.将所有数组加入到队列中
for (let i = 0; i < n; i++) {
queue.enqueue(i)
}
// 3.判断队列中是否还有数字
while(queue.size()>1) {
for(let i = 1; i<m; i++) {
queue.enqueue(queue.dequeue()!)
}
queue.dequeue()
}
return queue.dequeue()!
}
console.log(lastRemaining(5,3));//3
console.log(lastRemaining(10,17));//2
动态规划思想实现:
function lastRemainingOptimized(n: number, m: number): number {
if (n <= 0 || m <= 0) {
throw new Error("参数 n 和 m 必须大于 0");
}
let result = 0;
for (let i = 2; i <= n; i++) {
result = (result + m) % i;
}
return result;
}
// 测试用例
console.log(lastRemainingOptimized(5, 3)); // 输出: 3
console.log(lastRemainingOptimized(10, 17)); // 输出: 2