你们好,我是阿濠,今篇内容跟你们分享的是数据结构之栈,很高兴分享到segmentfault与你们一块儿学习交流,初次见面请你们多多关照,一块儿学习进步.
官方定义:栈(stack)是一个后进先出的线性表,它要求只在表尾作进行删除和插入操做。
栈:后进者先出,先进者后出
,这就是典型的栈结构。java
举个例子:就像叠盘子
同样,后来放的盘子老是在上面,拿的时候也是从上面拿,也就是先拿后来放上面的盘子,最后拿最先放的盘子。segmentfault
栈是一种重要的线性结构,栈是线性表的一种形式,在生活中,咱们的浏览器,每点击一次“后退”都是返回最近的一次浏览页面,至关于就是后进先出数组
栈有一些特殊限制:
1.栈元素必须后进先出
2.栈的操做只能在这个线性表的表尾进行
3.对于栈来讲,表尾则是栈顶(Top),表头则是栈底(bottom)浏览器
由于栈的本质是线性表,线性表有两种存储方式,因此栈也分两种存储方式分别为栈的顺序存储结构、栈的链式存储结构数据结构
栈的插入操做(Push)叫作进栈,也称为入栈,对于顺序栈的进栈操做只需将新的数据元素存入栈内,而后让记录栈内元素个数的变量加1,程序便可再次经过arr[size-1]从新访问新的栈顶元素。进栈操做示意图以下:学习
因为顺序栈底层一般会采用数组来保存数据元素,所以可能出现的状况是:当程序试图让一个数据元素进栈时,底层数据已满,那么就必须扩充底层数组的长度来容纳新进栈的数据元素。spa
栈的删除操做(Pop)叫作出栈,也称为弹栈,对于顺序栈的出栈操做而言,须要将栈顶元素弹出栈,程序要作两件事。3d
对于删除操做来讲,只要让记录栈内元素个数的size减1,程序便可经过arr[size-1]访问到新的栈顶元素。但不要忘记释放原来栈顶的数组引用,不然会引发内存泄漏。code
栈比普通线性表的功能更弱,栈是一种被限制过的线性表,只能从栈顶插入,删除数据元素。blog
能够采用单链表来保存栈中全部元素,这种链式结构的栈也被称为栈链。对于栈链而言,栈顶元素不断地改变,程序只要使用一个top引用来记录当前的栈顶元素便可。
链式的进栈操做,只须要作几件件事:
链式的出栈操做,只须要作几件件事:
从空间利用率的角度说,链栈的空间利用率比顺序栈的空间利用率要高一些。
java中有封装好的类,能够直接调用
push(element)
: 添加一个新元素到栈顶位置.pop()
:移除栈顶的元素,同时返回被移除的元素。peek()
:返回栈顶的元素,不对栈作任何修改(仅仅返回栈顶的元素)。isEmpty()
:若是栈里没有任何元素就返回true
,不然返回false
。clear()
:移除栈里的全部元素。size()
:返回栈里的元素个数。这个方法和数组的length
属性很相似。咱们能够作一个二进制转换十进制的方式去看看栈的后进先出,从数学的角度来讲二进制转换为十进制是最低位起去乘以N位的2^(n-1),而后所有加起来
简单的来讲示例二进制:1000 转换成十进制为8 why?
代入公式:0*2^(1-1)+0*2^(2-1)+0*2^(3-1)+1*2^(4-1)=0+0+0+8
假设咱们输入的数字是11001001这样的二进制数,那么放入栈就是
若是就会发现top栈顶就是最低位,依次算完发现栈底就是最高位
经过两个栈
实现的这个功能的
一个栈保存操做数
,另外一个栈保存运算符
,咱们从左到右遍历表达式
1.当遇到数字时,将其压入操做数栈;
2.当遇到运算符时,就与运算符栈的栈顶元素进行比较。
若是比运算符栈顶元素的优先级高,就将当前运算符压入栈;
若是比运算符栈的栈顶元素的优先级低或相同,那么就从操做数栈的栈顶取2个操做数,而后进行计算,再把计算完成的结果压入操做数栈,继续比较。
下面咱们举个例子:3+5*8-6这个表达式
好比你顺序查看了 a,b,c 三个页面,咱们就依次把 a,b,c 压入栈,这个时候,两个栈的数据就是这个样子:
当你经过浏览器的后退按钮,从页面 c 后退到页面 a 以后,咱们就依次把 c 和 b 从栈 X 中弹出,而且依次放入到栈 Y。这个时候,两个栈的数据就是这个样子:
这个时候你又想看页面 b,因而你又点击前进按钮回到 b 页面,咱们就把 b 再从栈 Y 中出栈,放入栈 X 中。此时两个栈的数据是这个样子:
这个时候,你经过页面 b 又跳转到新的页面 d 了,页面 c 就没法再经过前进、后退按钮重复查看了,因此须要清空栈 Y。此时两个栈的数据这个样子:
最长有效括号
题目描述: 给定一个只包含 '('
和')'
的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"
示例 2:
输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"
// 解法一:栈+暴力 public boolean isValid(String s) { // 判断任何一个子字符串s是否有效 Stack<Character> stack = new Stack<Character>(); for (int i = 0; i < s.length(); i++) { if (s.charAt(i) == '(') { stack.push('('); } else if (!stack.empty() && stack.peek() == '(') { stack.pop(); } else { return false; } } return stack.empty(); } //* 时间复杂度 O(n^2) 空间复杂度 O(n) * public int longestValidBracketLengthOne(String s) { int maxLength = 0; for (int i = 0; i < s.length(); i++) { for (int j = i + 2; j <= s.length(); j+=2) { if (isValid(s.substring(i, j))) { maxLength = Math.max(maxLength, j - i); } } } return maxLength; }
假设咱们按照思路输入")())" 初始的时候maxLength=0
1.i=0时,j=2,进入isValid方法的s=")(",这时的stack=0,方法里的for循环i=0时,无符合要求,直接return false结束j+=2
2.j=4,进入isValid方法的s=")())"这时的stack=0,方法里的for循环i=0时,无符合要求,直接return false结束i++
3.i=1,j=3,进入isValid方法的s="()",方法里的for循环i=0时,符合第一个if则push加入栈,stack=1,i++判断i=1时,不符合第一个if,符合第二个if,由于刚刚加入栈的栈顶='(',这时作了出栈的操做,stack=0,结束方法此时maxLength=3-1=2 结束i++
4.i=2,j=2,进入isValid方法的s="))",不符合for循环,j=4,j=4,进入isValid方法的s=")())",也不符合..
........
此方法一外面for循环作一次,里面for也要作一次,即作n*n次,因此时间复杂度 O(n^2)
// 解法二:栈 public int longestValidBracketLengthTwo(String s) { if (s == null || s.length() == 0) { return 0; } int maxLength = 0; // 设定返回值 即最长有效括号的长度 int n = s.length(); // 保存须要循环的次数 也就是字符串的最初长度 char[] sArr = s.toCharArray(); // 字符串生成相应的字符数组 Stack<Integer> stack = new Stack<Integer>(); // 建立系统的栈类 存放字符数组中的下标 stack.push(-1); // -1 入栈用于处理边界条件 for (int i = 0; i < n; i++) { // 循环第i项对应的字符是 ')' // 且 stack.size() > 1 表示栈不为空 // 且 必须保证栈顶元素(下标 )对应的字符是 '(' if (sArr[i] == ')' && stack.size() > 1 && sArr[stack.peek()] == '(') { stack.pop(); // 对应字符'(' 的栈顶元素(下标 ) 出栈 // 记录最长长度 由于i是线性往前增长 而栈顶元素(下标 )是线性增减 maxLength = Math.max(maxLength, i - stack.peek()); } else { // 其余状况,直接将当前位置入栈 stack.push(i); } } return maxLength; }
假设咱们按照思路输入")())" 初始的时候maxLength=0
我定义n=输入的字符串长度也是循环的次数,并生成相对应的char[]字符数组,与系统栈,
给栈定义边界为-1,避免对应不上char字符数组
并根据char数组肯定循环次数,从而先找到')'的下标再判断栈的栈顶是否'(',若是对应的下标不符合要求则将下标加入栈
咱们找到下标0是')',可是目前的栈顶的值对应数组不是'(',因此将下标0放入栈里,对应的')'称为栈顶。
下标1对应的数组是'('不是咱们要找的值
下标2对应的数组是')',符合咱们的要求,目前的栈顶是1,对应的数组是'('符合要求,咱们将目前的栈顶弹出,此时站的个数由3-1=2,且栈顶对应的值就是0,maxLength=2-0
......
由于只须要将字符串变成char数组,而且将数组里的char判断符合逻辑问题,因此是 时间复杂度 O(n) 空间复杂度 O(n)