题目描述1
笔者解答1.1
笔者分析1.2
虽然执行结果通过了,但看到执行用时和内存消耗,真是有点头疼。想了想,这次刷的是栈,但自己根本没有用到栈,看了些大佬们的解法,做了些总结,呃。。。好像都差不多。。。(过)。
题目描述2
笔者解答2.1
class Solution {
public int calPoints(String[] ops) {
int i;
int score=0;
int last_get=0;
int last_get2=0;
int last_score=0;
int last_score2=0;
int last_score3=0;
for(i=0;i<ops.length;i++){
last_get=score-last_score;
last_get2=last_score-last_score2;
if(ops[i].equals("+"))
{
last_score3=last_score2;
last_score2=last_score;
last_score=score;
score+=(last_get+last_get2);
}else if(ops[i].equals("D"))
{
last_score3=last_score2;
last_score2=last_score;
last_score=score;
score+=(last_get*2);
}else if(ops[i].equals("C"))
{
score=last_score;
last_score=last_score2;
last_score2=last_score3;
}
else
{
int num2 = Integer.parseInt(ops[i]);
last_score3=last_score2;
last_score2=last_score;
last_score=score;
score+=num2;
}
}
return score;
}
}
笔者分析2.2
着实是很菜啊,这题只过了题目里的两个案例,而且写的还那么复杂。看了些大佬们的解法,思路和我的完全不同,很简洁。他们并不是存储每次的总分,而是存储每次得到的分数,最后求和来算总分,这比我每次都要通过计算上次获得的分数简单多了,而且他们的方法可以存储每次的得分,而我的只能是近几次的,肯定是通过不了的。下面给出大佬们的解法。还有,千万别急着写代码,一定要理清思路,更别曲解题目意思。
class Solution {
public int calPoints(String[] ops) {
int[] arr = new int[ops.length];
int i=0;
for(String s:ops){
switch (s){
case "+":arr[i]=arr[i-1]+arr[i-2];i++;break;
case "D":arr[i]=2*arr[i-1];i++;break;
case "C":arr[i-1]=0;i--;break;
default:
arr[i]=Integer.valueOf(s);
i++;
}
}
int sum=0;
for (int j = 0; j <arr.length ; j++) {
sum+=arr[j];
}
return sum;
}
}
题目描述3
笔者解答3.1
class CQueue{
LinkedList<Integer> stack1;
LinkedList<Integer> stack2;
public CQueue()
{
stack1=new LinkedList<>();
stack2=new LinkedList<>();
}
public void appendTail(int value)
{
stack1.add(value);
}
public int deleteHead()
{
if(stack2.isEmpty())
{
if(stack1.isEmpty())return -1;
while(!stack1.isEmpty())
{
stack2.add(stack1.pop());
}
return stack2.pop();
}else return stack2.pop();
}
}
笔者分析3.2
基本思想是用两个栈,其中一个用于存储数据即入队,另一个栈用于输出数据即出队,两个栈的关系是将栈A的数据以出栈的方式存入栈B,这样两个栈内的内容顺序便完全相反。
题目描述4
笔者解答4.1
class MinStack {
LinkedList<Integer> stack;
int min;
int top;
/** initialize your data structure here. */
public MinStack() {
stack=new LinkedList<>();
}
public void push(int x) {
if(stack.isEmpty())
{
stack.add(x);
min=x;
top=x;
}
else
{
stack.add(x);
if(x>top)top=x;
if(x<min)min=x;
}
}
public void pop() {
int x= stack.pop();
}
public int top() {
return top;
}
public int min() {
return min;
}
}
笔者分析4.2
时间复杂度为O(1),第一次插入元素时,显然该元素为最小值,之后每次插入一个元素都和当前最小值比较,更新最小值。但是,笔者的写法有些问题,就是当栈内弹出元素时,栈中的最小值并未更新,而如果说保存最小值和第二小的值,那么如果连续弹出几个元素,依然不奏效。这里遇到的问题是,如何保存每次的最小值,单从这一点和上面第二题类似。首先我们应该摆脱这样一个思维,链表不仅仅可以保存它自身的值和它下一个结点的值,又或者说上一个结点的值,它还可以保存任何你需要的数据,包括这题中的最小值。所以我们定义链表结构的时候,还应该多加一个最小值的数据,即从头结点到当前结点为止,最小值是多少,从而能够实现时间复杂度为O(1)的查询最小值,下面给出代码。
class MinStack {
private Node head;
/** initialize your data structure here. */
public MinStack() {
}
public void push(int x) {
if(head==null)
head=new Node(x,x,null);
else
head=new Node(x,Math.min(head.min,x),head);
}
public void pop() {
head=head.next;
}
public int top() {
return head.val;
}
public int min() {
return head.min;
}
private class Node{
int val;
int min;
Node next;
public Node(int val, int min,Node next){
this.val=val;
this.min=min;
this.next=next;
}
}
}
题目描述5
笔者解答5.1
class Solution {
public boolean isValid(String s) {
LinkedList<Character> stack=new LinkedList<>();
for(int i=0;i<s.length();i++)
{
if(s.charAt(i)=='(')stack.push('(');
if(s.charAt(i)=='[')stack.push('[');
if(s.charAt(i)=='{')stack.push('{');
if(s.charAt(i)==')'){
if(stack.isEmpty()) return false;
char c= stack.pop();
if(c!='(')return false;
}
if(s.charAt(i)==']'){
if(stack.isEmpty()) return false;
Character c= stack.pop();
if(c!='[')return false;
}
if(s.charAt(i)=='}'){
if(stack.isEmpty()) return false;
char c= stack.pop();
if(c!='{')return false;
}
}
if(stack.isEmpty())return true;
else return false;
}
}
笔者分析5.2
看到大佬们的解答,越发觉得自己的代码不忍直视,他们的解法真的太巧妙了,而自己的只是普通的不能再普通了。下面分析一下大佬们的思路。记住,尽管传入的是一串字符,但只要能够实现统一功能,并非一定要存入原字符串,可适当变形。同时如果可以逆序解决的问题,顺序一样能解决,可能还会方便不少。
class Solution {
public boolean isValid(String s) {
Stack<Character>stack = new Stack<Character>();
for(char c: s.toCharArray()){
if(c=='(')stack.push(')');
else if(c=='[')stack.push(']');
else if(c=='{')stack.push('}');
else if(stack.isEmpty()||c!=stack.pop())return false;
//如果一开始就是"]",")","}"符号的话,显然不成立,这是stack.isEmpty为真,返回false;
//否则,存入当前符号的匹配字符,判断下一个存入的字符是否相等,当然也可以存入下一个字符,判断前一个字符是否匹
//配,只不过,这样会麻烦许多,总之很巧妙吧
}
return stack.isEmpty();
}
}
题目描述6
笔者解答6.1
笔者分析6.2
虽然说方法用的不是太复杂,思路也还行,但是这执行用时和内存消耗也太大了,应该是substring捣的鬼。
题目描述7
笔者解答7.1
class Solution {
public int[] nextGreaterElement(int[] nums1, int[] nums2) {
int[] compare=new int[nums1.length];
for(int i=0;i<nums1.length;i++)
{
int a=nums1[i];
boolean get=false;
for(int j=0;j<nums2.length;j++)
{
if(nums2[j]==a)
{
get=true;
}
if(get&&nums2[j]>a)
{
compare[i]=nums2[j];break;
}
if(j==nums2.length-1)
{
compare[i]=-1;break;
}
}
}
return compare;
}
}
笔者分析7.2
自认为时间复杂度较高,但看了下数据貌似还行,但内存消耗有点大。
题目描述8
笔者解答8.2
class Solution {
public String removeDuplicates(String S) {
Stack<Character> stack=new Stack<Character>();
int length=0;
for(int i=0;i<S.length();i++)
{
if(stack.isEmpty()||stack.peek()!=S.charAt(i))
{
stack.push(S.charAt(i));
length++;
}
else
{
if(stack.peek()==S.charAt(i))
{
stack.pop();
length--;
}
}
}
char[] array=new char[length];
int i=length-1;
while(!stack.isEmpty())
{
array[i]=stack.pop();
i--;
}
String s = String.valueOf(array);
return s;
}
}
笔者分析8.3
这其实就是栈的一个典型应用,每次入栈时都与栈顶元素比较,若相同,则将栈顶元素弹出,若不相同则入栈。只不过最后有一个小问题,因为栈是先进后出的,如果直接输出栈的话,它字符顺序是完全相反的,所以多了一步将栈中的数据元素存入一个新的数组,带来的问题是占用了更多的内存。其它方法也都大同小异。
题目描述9
笔者解答9.1
class Solution {
public List<String> buildArray(int[] target, int n) {
List<String> list=new ArrayList<String>();
for(int i=0;i<target.length;i++){
if(i==0)
{
int c=target[i];
while(c>1){
list.add("Push");
list.add("Pop");
c--;
}
if(c==1)
list.add("Push");
}else
{
int c=target[i]-target[i-1];
while(c>1){
list.add("Push");
list.add("Pop");
c--;
}
if(c==1)
list.add("Push");
}
}
return list;
}
}
笔者分析9.2
这次的执行用时很客观,超过了百分之百的用户,但内存消耗属于垫底的那种,题目意思很简单,个人认为题目有多解,而且传入的参数n也是多余的。
题目描述10
笔者解答10.1
class MyStack {
Queue<Integer> queue;
Queue<Integer> queue2;
/** Initialize your data structure here. */
public MyStack() {
queue=new LinkedList<Integer>();
queue2=new LinkedList<Integer>();
}
/** Push element x onto stack. */
public void push(int x) {
if(queue.isEmpty())
while(!queue2.isEmpty())
{
queue.offer(queue2.poll());
}
queue.offer(x);
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
int num=0;
if(queue2.isEmpty()){
while(!queue.isEmpty()){
num=queue.poll();
if(!queue.isEmpty())
queue2.offer(num);
}}
else{
while(!queue2.isEmpty()){
num=queue2.poll();
if(!queue2.isEmpty())
queue.offer(num);
}
}
return num;
}
/** Get the top element. */
public int top() {
int num=0;
if(queue2.isEmpty()){
while(!queue.isEmpty()){
num=queue.poll();
queue2.offer(num);
}}
else{
while(!queue2.isEmpty()){
num=queue2.poll();
queue.offer(num);
}
}
return num;
}
/** Returns whether the stack is empty. */
public boolean empty() {
if(queue.isEmpty()&&queue2.isEmpty())
return true;
else
return false;
}
}
笔者分析10.2
我也不明白怎么写的这么复杂,肯定是有问题的,直到看到大佬们的解法才豁然开朗。要想实现栈,这里类比为将顺序改为逆序,那么你就得先存大的,再将之前小的存入。而这些小的需要保存起来,就是下面代码中的b。
class MyStack {
private Queue<Integer> a;//输入队列
private Queue<Integer> b;//输出队列
public MyStack() {
a = new LinkedList<>();
b = new LinkedList<>();
}
public void push(int x) {
a.offer(x);
// 将b队列中元素全部转给a队列
while(!b.isEmpty())
a.offer(b.poll());
// 交换a和b,使得a队列没有在push()的时候始终为空队列
Queue temp = a;
a = b;
b = temp;
}
public int pop() {
return b.poll();
}
public int top() {
return b.peek();
}
public boolean empty() {
return b.isEmpty();
}
}
总结
到这里,leetcode里栈的简单题部分就完结了,一共十六题,部分题相似度太高,博客里只介绍了其中十题,明天开始栈的中等题部分。