【JAVA刷题初阶】刷爆力扣第七弹——栈

文章目录

  • 前言:关于JAVA刷题
    • 第一题:回文链表
      • 题目描述
      • 示例
      • 提示
      • 题解
    • 第二题:棒球比赛
      • 题目描述
      • 示例
      • 提示
      • 题解
    • 第三题:比较含退格的字符串
      • 题目描述
      • 示例
      • 提示
      • 题解


前言:关于JAVA刷题

关于JAVA的学习出了看视频以外,那就是刷题了,朋友们,你们有没有过这样的感觉,在网上看了视频过后感觉自己什么都听懂了,但就是写题和做项目时无从下手,或者就是因为某个细节一直错一直改,那背后的原因是什么呢?四个字——题刷少了,这里新一建议去Leetcode看看,那里的题库资源很丰富,并且在全球都有广泛涉猎。不仅如此,这里还有 课程 + 刷题 + 面经 + 求职 + 讨论区分享解题思路,用过的人都说好
在这里插入图片描述
除此之外,我的建议是初学者从简单题开始练习,因为简单题是一切题的基础,一切的困难题都是从简单题衍生而来的,每天刷那么2~3题,后期再慢慢刷中等题,困难题,经过一段时间后会有很不错的提升
在这里插入图片描述
此外,在我们有一定的提升之后,我们便可以去刷剑指offer了,在这里预祝各位大学生以及初学者都拿到自己满意的offer!


第一题:回文链表


做题链接戳这里:234.回文链表

题目描述

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

示例

在这里插入图片描述

输入:head = [1,2,2,1]
输出:true

示例2
【JAVA刷题初阶】刷爆力扣第七弹——栈_第1张图片

输入:head = [1,2]
输出:false

提示

● 链表中节点数目在范围[1, 105] 内
● 0 <= Node.val <= 9

进阶:你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

题解

常规思路:

要判断回文链表,我们首先想到的是倒排,然后同时遍历,如果最后都能一直匹配上那么它就是回文链表,那么关键是我们怎么把链表倒过来呢?在定义一个链表尾插?不不不,既然这是单链表我们用栈是不是会更好呢,遍历链表的同时入栈即可,后续直接在遍历一遍链表,看出栈元素是否匹配即可

class Solution {
    public boolean isPalindrome(ListNode head) {
        Stack<Integer> stack = new Stack<>();
        ListNode node = head;
        while (node != null){
            stack.push(node.val);
            node = node.next;
        }
        node = head;
        while (node != null){
            if (!stack.empty() && node.val != stack.pop()){
                return false;
            }
            node = node.next;
        }
        return stack.empty();
    }
}

【JAVA刷题初阶】刷爆力扣第七弹——栈_第2张图片

快慢指针压半栈

上述方法确实可以,也挺简单,但是这时间复杂度实在有点不够看,那么我们有更好的方法吗?当然有,既然它满足回文链表,那么我们就找一个中间节点,把这个节点之前的数据压栈,然后退出循环,然后拿栈顶元素跟之后的元素比较即可,入过不相等退出循环,返回栈空即可。

class Solution {
    public boolean isPalindrome(ListNode head) {
        Stack<Integer> stack = new Stack<>();
        ListNode fast = head;
        ListNode slow = head;
        while (fast != null && fast.next != null){
            stack.push(slow.val);
            fast = fast.next.next;
            slow = slow.next;
        }
        if (fast != null && fast.next == null){
            slow = slow.next;
        }
        while (slow != null){
            if (!stack.empty() && slow.val == stack.peek()){
                stack.pop();
            }else{
                break;
            }
            slow = slow.next;
        }
        return stack.empty();
    }
}

【JAVA刷题初阶】刷爆力扣第七弹——栈_第3张图片
快慢指针头插法

加油!我们的时间已经减少了接近一半了,我们想想压栈弹出肯定是需要时间的,我们能否模拟栈呢,将其压栈弹出的部分再优化掉,当然可以,只需生成一个傀儡节点即可,然后利用快慢指针将其头插,最后遍历新生成的的两个链表即可(实际上是将该链表分割成两部分,时间复杂度O(n),空间复杂度O(1)),缺点就是代码量较大。

class Solution {
    public boolean isPalindrome(ListNode head) {
        if (head == null){
            return false;
        }

        ListNode fast = head;
        ListNode slow = head;
        ListNode newHead = new ListNode(-1);
        ListNode tmp = newHead;
        ListNode cur = head;
        while (fast != null && fast.next != null){
            fast = fast.next.next;
            cur = cur.next;
            slow.next = tmp;
            tmp = slow;
            slow = cur;
        }
        if (fast != null && fast.next == null){
            slow = slow.next;
        }
        while (slow != null){
            if (slow.val != tmp.val){
                return false;
            }
            slow = slow.next;
            tmp = tmp.next;
        }
        return true;
    }
}

【JAVA刷题初阶】刷爆力扣第七弹——栈_第4张图片
数学方法

最后我们来说说这个方法:数学文化,博大精深,八行代码,完全爆破

class Solution {
    public boolean isPalindrome(ListNode head) {
        int s1 = 0,s2 = 0,t = 1;

        while(head != null) {
            s1 = s1*10 + head.val;
            s2 = s2 + t*head.val;
            t = t*10;
            head = head.next;
        }
        return s1 == s2;
    }
}

【JAVA刷题初阶】刷爆力扣第七弹——栈_第5张图片

第二题:棒球比赛


做题链接戳这里,682.棒球比赛

题目描述

你现在是一场采用特殊赛制棒球比赛的记录员。这场比赛由若干回合组成,过去几回合的得分可能会影响以后几回合的得分。

比赛开始时,记录是空白的。你会得到一个记录操作的字符串列表 ops,其中 ops[i] 是你需要记录的第 i 项操作,ops 遵循下述规则:

整数 x - 表示本回合新获得分数 x
“+” - 表示本回合新获得的得分是前两次得分的总和。题目数据保证记录此操作时前面总是存在两个有效的分数。
“D” - 表示本回合新获得的得分是前一次得分的两倍。题目数据保证记录此操作时前面总是存在一个有效的分数。
“C” - 表示前一次得分无效,将其从记录中移除。题目数据保证记录此操作时前面总是存在一个有效的分数。
请你返回记录中所有得分的总和。

示例

输入:ops = [“5”,“2”,“C”,“D”,“+”]
输出:30
解释:
“5” - 记录加 5 ,记录现在是 [5]
“2” - 记录加 2 ,记录现在是 [5, 2]
“C” - 使前一次得分的记录无效并将其移除,记录现在是 [5].
“D” - 记录加 2 * 5 = 10 ,记录现在是 [5, 10].
“+” - 记录加 5 + 10 = 15 ,记录现在是 [5, 10, 15].
所有得分的总和 5 + 10 + 15 = 30

示例2

输入:ops = [“5”,“-2”,“4”,“C”,“D”,“9”,“+”,“+”]
输出:27
解释:
“5” - 记录加 5 ,记录现在是 [5]
“-2” - 记录加 -2 ,记录现在是 [5, -2]
“4” - 记录加 4 ,记录现在是 [5, -2, 4]
“C” - 使前一次得分的记录无效并将其移除,记录现在是 [5, -2]
“D” - 记录加 2 * -2 = -4 ,记录现在是 [5, -2, -4]
“9” - 记录加 9 ,记录现在是 [5, -2, -4, 9]
“+” - 记录加 -4 + 9 = 5 ,记录现在是 [5, -2, -4, 9, 5]
“+” - 记录加 9 + 5 = 14 ,记录现在是 [5, -2, -4, 9, 5, 14]
所有得分的总和 5 + -2 + -4 + 9 + 5 + 14 = 27

提示

● 1 <= ops.length <= 1000
● ops[i] 为 “C”、“D”、“+”,或者一个表示整数的字符串。整数范围是 [-3 * 104, 3 * 104]
● 对于 “+” 操作,题目数据保证记录此操作时前面总是存在两个有效的分数
● 对于 “C” 和 “D” 操作,题目数据保证记录此操作时前面总是存在一个有效的分数

题解

我们读了一遍题过后,发现共有四种操作,每种操作会对列表内元素做修改,那我们何不如用栈来模拟这个列表,利用栈的压栈和弹出来分别实现这四种操作,注意最后要检查栈是否为空,不为空结果需加上栈内剩余元素,还要注意输入的是字符串数组,我们需要压栈是需要强转为int型

class Solution {
    public int calPoints(String[] operations) {
        Stack<Integer> stack = new Stack<>();

        for (int i = 0; i < operations.length; i++) {
            String str = operations[i];
            switch (str){
                case "+":
                    int num1 = stack.pop();
                    int num2 = stack.peek();
                    stack.push(num1);
                    stack.push(num1 + num2);
                    break;
                case "D":
                    int num = stack.peek() * 2;
                    stack.push(num);
                    break;
                case "C":
                    stack.pop();
                    break;
                default:
                    stack.push(Integer.parseInt(str));
                    break;
            }
        }
        int ret = 0;
        while (!stack.empty()){
            ret += stack.pop();
        }
        return ret;
    }
}

【JAVA刷题初阶】刷爆力扣第七弹——栈_第6张图片

数组模拟栈

还是跟上一道题一个道理,压栈弹出是需要时间的,我们用数组模拟栈即可实现访问元素的复杂度为线性

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;
    }
}

【JAVA刷题初阶】刷爆力扣第七弹——栈_第7张图片

第三题:比较含退格的字符串


做题链接戳这里:844.比较含退格的字符串

题目描述

给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。

注意:如果对空文本输入退格字符,文本继续为空。

示例

输入:s = “ab#c”, t = “ad#c”
输出:true
解释:s 和 t 都会变成 “ac”

示例2

输入:s = “ab##”, t = “c#d#”
输出:true
解释:s 和 t 都会变成 “”。

示例3

输入:s = “a#c”, t = “b”
输出:false
解释:s 会变成 “c”,但 t 仍然是 “b”。

提示

● 1 <= s.length, t.length <= 200
● s 和 t 只含有小写字母以及字符 ‘#’

进阶:你可以用 O(n) 的时间复杂度和 O(1) 的空间复杂度解决该问题吗?

题解

常规思路

怎么办?这是比较两个字符串啊,而且还包含退格符,我们仔细想想,我们用栈试试,遇到普通元素压栈,遇到退格符弹出,一个栈不够,那就两个!最后直接两个栈依次出栈比较即可

class Solution {
    public boolean backspaceCompare(String s, String t) {
        Stack<Character> stack1 = new Stack<>();
        Stack<Character> stack2 = new Stack<>();

        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (c == '#'){
                if (!stack1.empty()) {
                    stack1.pop();
                }
            }else{
                stack1.push(c);
            }
        }
        for (int i = 0; i < t.length(); i++) {
            char c = t.charAt(i);
            if (c == '#'){
                if (!stack2.empty()) {
                    stack2.pop();
                }
            }else{
                stack2.push(c);
            }
        }
        while (!stack1.empty() && !stack2.empty()){
            if (stack1.peek() == stack2.peek()){
                stack1.pop();
                stack2.pop();
            }else{
                break;
            }
        }
        return stack1.empty() && stack2.empty();
    }
}

【JAVA刷题初阶】刷爆力扣第七弹——栈_第8张图片

优化思想

首先,我们两个字符串执行了同样的代码,那么干嘛不将它封装成一个方法,然后两个字符串分别调用即可,此外,还是我们的统一思想:压栈弹出浪费时间,数组模拟节省时间

class Solution {
    public boolean backspaceCompare(String s, String t) {
        return getString(s).equals(getString(t));
    }
    public String getString(String s){
        char[] ret = s.toCharArray();
        int n = ret.length;

        int slow = 0;
        for (int fast = 0; fast < n; fast++) {
            if (ret[fast] == '#'){
                if (slow > 0){
                    slow--;
                }
            }else{
                ret[slow++] = ret[fast];
            }
        }
        return new String(ret,0,slow);
    }
}

【JAVA刷题初阶】刷爆力扣第七弹——栈_第9张图片

你可能感兴趣的:(JAVA刷爆力扣训练营,java,leetcode,链表)