怒刷LeetCode的第8天(Java版)

news2024/12/26 15:34:29

目录

第一题

题目来源

题目内容

解决方法

方法一:双指针和排序

​编辑第二题

题目来源

题目内容

解决方法

方法一:双指针

方法二:递归

方法三:快慢指针

方法四:栈

第三题

题目来源

题目内容

解决方法

方法一:栈


第一题

题目来源

18. 四数之和 - 力扣(LeetCode)

题目内容

解决方法

方法一:双指针和排序

根据题目要求,可以使用双指针和排序法来解决这个问题。

使用双指针解决四数之和问题的算法思路如下:

1、对数组进行排序,将其从小到大排列。

2、使用两重循环分别枚举前两个数,其中第一个数的下标范围是0到n-4,第二个数的下标范围是第一个数的下标加1到n-3。

4、在两重循环中,使用双指针分别指向当前枚举的两个数之后的位置。

5、每次计算四个数的和,并根据和与目标值的比较结果进行如下操作:

  • 如果和等于目标值,将四个数加入答案。
  • 如果和小于目标值,将左指针右移一位。
  • 如果和大于目标值,将右指针左移一位。
  • 同时,如果左指针或右指针指向的数字与上一次迭代的数字相同,继续移动指针直到遇到不同的数字。

6、循环结束后,返回所有符合条件的四个数的组合。

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> quadruplets = new ArrayList<List<Integer>>();
        if (nums == null || nums.length < 4) {
            return quadruplets;
        }
        Arrays.sort(nums);
        int length = nums.length;
        for (int i = 0; i < length - 3; i++) {
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            if ((long) nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
                break;
            }
            if ((long) nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target) {
                continue;
            }
            for (int j = i + 1; j < length - 2; j++) {
                if (j > i + 1 && nums[j] == nums[j - 1]) {
                    continue;
                }
                if ((long) nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {
                    break;
                }
                if ((long) nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target) {
                    continue;
                }
                int left = j + 1, right = length - 1;
                while (left < right) {
                    long sum = (long) nums[i] + nums[j] + nums[left] + nums[right];
                    if (sum == target) {
                        quadruplets.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
                        while (left < right && nums[left] == nums[left + 1]) {
                            left++;
                        }
                        left++;
                        while (left < right && nums[right] == nums[right - 1]) {
                            right--;
                        }
                        right--;
                    } else if (sum < target) {
                        left++;
                    } else {
                        right--;
                    }
                }
            }
        }
        return quadruplets;
    }
}

复杂度分析:

  • 时间复杂度为O(n^3),其中n是数组的长度。这是因为代码中有两重循环,加上双指针的遍历,总的时间复杂度为O(n^2)。而在双指针的遍历过程中,左右指针最多各自遍历一次数组,所以时间复杂度为O(n)。
  • 空间复杂度方面,代码只使用了常数级别的额外空间,主要是存储结果列表,所以空间复杂度为O(1)。

总结起来,该算法的时间复杂度为O(n^3),空间复杂度为O(1)。需要注意的是,在代码中已经进行了一些剪枝操作,以优化算法的效率。

LeetCode运行结果:

第二题

题目来源

19. 删除链表的倒数第 N 个结点 - 力扣(LeetCode)

题目内容

解决方法

方法一:双指针

这道题可以使用双指针来实现。具体做法是,先让第一个指针往前移动n个位置,然后同时移动第一个指针和第二个指针,直到第一个指针到达链表尾部。此时,第二个指针所指向的节点就是要删除的节点的前一个节点,我们只需要将该节点的next指针指向下一个节点,即可完成删除操作。

需要注意的几点是:

  • 要处理删除头结点的情况;
  • 链表中可能只有一个节点。
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
    if (head == null) {
        return null;
    }
    
    ListNode dummy = new ListNode(0, head);
    ListNode first = head;
    ListNode second = dummy;
    
    for (int i = 0; i < n; i++) {
        first = first.next;
    }
    
    while (first != null) {
        first = first.next;
        second = second.next;
    }
    
    second.next = second.next.next;
    
    return dummy.next;
}

}

复杂度分析:

  • 对于给定的链表,我们只需要进行一次遍历即可找到要删除的节点的前一个节点。因此,时间复杂度为O(n),其中n是链表的长度。
  • 在空间复杂度方面,我们只使用了常数级别的额外空间,主要是两个指针变量和一个虚拟头节点。因此,空间复杂度为O(1)。

综上所述,该算法的时间复杂度为O(n),空间复杂度为O(1)。

LeetCode运行结果:

方法二:递归

除了双指针法之外,我们还可以使用递归来解决这个问题。具体做法是,在递归的过程中,使用一个计数器来记录当前遍历到的节点位置,并从链表的末尾开始向前遍历。当计数器等于n时,将当前节点的next指针指向下一个节点的next指针,即完成删除操作。

class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
    if (head == null) {
        return null;
    }
    
    int count = removeHelper(head, n);
    
    // 如果计数器等于n,表示要删除的是头结点
    if (count == n) {
        return head.next;
    }
    
    return head;
}

private int removeHelper(ListNode node, int n) {
    if (node == null) {
        return 0;
    }
    
    int count = removeHelper(node.next, n) + 1;
    
    // 如果计数器等于n+1,表示要删除的是当前节点的下一个节点
    if (count == n + 1) {
        node.next = node.next.next;
    }
    
    return count;
}
}

该方法的思路是通过递归实现回溯,每次递归返回当前节点所处的位置。在返回的过程中,不断判断计数器的值是否等于n或n+1,并进行相应的删除操作。

复杂度分析:

  • 时间复杂度:在递归过程中,需要遍历整个链表,即O(n)次递归调用。每次递归操作都需要O(1)的时间,因此总体时间复杂度为O(n)。
  • 空间复杂度:递归调用会占用栈空间,最坏情况下,递归的深度为链表的长度n,因此空间复杂度为O(n),除去递归栈空间外,不需要额外的空间。

LeetCode运行结果:

方法三:快慢指针

另一种常见的思路是使用快慢指针。首先,我们让快指针向前移动n个位置。然后,同时移动快指针和慢指针,直到快指针达到链表尾部。此时,慢指针所指的节点就是要删除的节点的前一个节点,我们只需将其next指针指向下一个节点,即可完成删除操作。

class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
    if (head == null) {
        return null;
    }
    
    ListNode dummy = new ListNode(0, head);
    ListNode fast = dummy;
    ListNode slow = dummy;
    
    // 快指针先向前移动n个位置
    for (int i = 0; i < n; i++) {
        fast = fast.next;
    }
    
    // 同时移动快慢指针,直到快指针达到链表尾部
    while (fast.next != null) {
        fast = fast.next;
        slow = slow.next;
    }
    
    // 删除目标节点
    slow.next = slow.next.next;
    
    return dummy.next;
}

}

该方法的思路是通过快慢指针的差距来定位要删除的节点的前一个节点。快指针先向前移动n个位置,然后同时移动快慢指针,直到快指针到达链表尾部。这样,慢指针所指的节点就是要删除的节点的前一个节点。 

复杂度分析: 

  • 时间复杂度:需要遍历整个链表,除了初始化指针外,只需一次遍历即可完成任务。因此时间复杂度为O(n)。
  • 空间复杂度:只使用了常数级别的额外空间,即定义的指针变量,因此空间复杂度为O(1)。

注意:递归解法和快慢指针解法的时间复杂度都是O(n),其中递归解法的空间复杂度为O(n),而快慢指针解法的空间复杂度为O(1)。因此,在大多数情况下,推荐使用快慢指针解法,因为它的空间复杂度更低。

LeetCode运行结果:

方法四:栈

  • 首先,遍历链表并将每个节点都压入栈中。
  • 然后,从栈顶开始弹出节点,同时计数。
  • 当计数等于n时,表示栈顶节点就是要删除的节点。此时,只需修改相应的指针即可完成删除操作。
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
    if (head == null) {
        return null;
    }
    
    Stack<ListNode> stack = new Stack<>();
    ListNode dummy = new ListNode(0);
    dummy.next = head;
    ListNode current = dummy;
    
    // 将链表节点依次压入栈中
    while (current != null) {
        stack.push(current);
        current = current.next;
    }
    
    // 弹出第n个节点,并删除
    for (int i = 0; i < n; i++) {
        stack.pop();
    }
    ListNode prev = stack.peek();
    prev.next = prev.next.next;
    
    return dummy.next;
}
}

复杂度分析:

  • 时间复杂度:遍历链表将节点压入栈中需要O(n)的时间,弹出第n个节点并删除需要O(n)的时间,因此总体时间复杂度为O(n)。
  • 空间复杂度:创建了一个栈来存储链表节点,栈的空间消耗取决于链表的长度,所以空间复杂度为O(n)。

综上所述,使用栈解法删除链表中倒数第n个节点的时间复杂度为O(n),空间复杂度为O(n)。相较于快慢指针解法的O(1)的空间复杂度,栈解法的空间复杂度较高。因此,在大多数情况下,推荐使用快慢指针解法。

LeetCode运行结果:

第三题

题目来源

20. 有效的括号 - 力扣(LeetCode)

题目内容

解决方法

方法一:栈

这个问题可以使用栈来解决。我们可以遍历字符串,当遇到左括号时,将其入栈,当遇到右括号时,判断栈顶元素是否与当前右括号匹配。如果匹配,则将栈顶元素出栈,继续遍历;如果不匹配或栈为空,则说明字符串无效。

import java.util.Stack;
class Solution {
   public boolean isValid(String s) {
    Stack<Character> stack = new Stack<>();
    for (char c : s.toCharArray()) {
        if (c == '(' || c == '{' || c == '[') { // 遇到左括号,入栈
            stack.push(c);
        } else if (c == ')' || c == '}' || c == ']') { // 遇到右括号,判断是否匹配
            if (stack.isEmpty()) {
                return false; // 栈为空,无法匹配
            }
            char top = stack.pop(); // 弹出栈顶元素
            if ((c == ')' && top != '(') ||
                (c == '}' && top != '{') ||
                (c == ']' && top != '[')) {
                return false; // 括号不匹配
            }
        }
    }
    return stack.isEmpty(); // 如果栈为空,则所有括号都匹配成功
}
}

复杂度分析:

在遍历字符串时,时间复杂度为O(n),其中n是字符串的长度。同样,使用了一个栈来存储字符,空间复杂度也为O(n)。因此,该解法的时间复杂度和空间复杂度均为O(n)。

LeetCode运行结果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1022984.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python实现查询一个文件中的pdf文件中的关键字

要求&#xff0c;查询一个文件中的pdf文件中的关键字&#xff0c;输出关键字所在PDF文件的文件名及对应的页数。 import os import PyPDF2def search_pdf_files(folder_path, keywords):# 初始化结果字典&#xff0c;以关键字为键&#xff0c;值为包含关键字的页面和文件名列表…

数据分析三剑客之一:Pandas详解

目录 1 Pandas介绍 2 Pandas的安装与导入 2.1 Pandas模块安装 2.2 Pandas模块导入 3 pandas数据结构及函数 3.1 Series结构 3.1.1 ndarray创建Series对象 3.1.2 dict创建Series对象 3.1.3 标量创建Series对象 3.1.4 位置索引访问Series数据 3.1.5 标签索引访问Series…

华为云HECS安装docker

1、运行安装指令 yum install docker都选择y&#xff0c;直到安装成功 2、查看是否安装成功 运行版本查看指令&#xff0c;显示docker版本&#xff0c;证明安装成功 docker --version 或者 docker -v 3、启用并运行docker 3.1启用docker 指令 systemctl enable docker …

【Linux基础】第七章:搜索查找-find查找文件或者目录

find命令是根据文件属性进行查找的&#xff0c;如文件名&#xff0c;文件大小&#xff0c;所有者&#xff0c;所有组&#xff0c;是否为空&#xff0c;访问时间&#xff0c;修改时间等。 基本格式&#xff1a; find path [options] 先定位到etc 目录下 cd /etc1.按照文件名查找…

成集云 | 金蝶EAS集成聚水潭ERP(金蝶EAS主管库存)| 解决方案

源系统成集云目标系统 方案介绍 金蝶EAS是一款全球首款融合TOGAF标准SOA架构的企业管理软件&#xff0c;专门为大中型企业设计&#xff0c;以“创造无边界信息流”为产品设计理念&#xff0c;支持云计算、SOA和动态流程管理的整合技术平台。 聚水潭是一款以SaaS ER…

IP地址定位的基本原理

IP地址定位是一种用于确定互联网上设备地理位置的技术&#xff0c;它是网络管理、安全监控和市场定位等领域的重要工具。本文将深入探讨IP地址定位的基本原理&#xff0c;以及它是如何工作的。 1. IP地址的结构 IP地址是互联网上的设备的唯一标识符&#xff0c;它由一系列数字…

深入理解算法的时间复杂度

文章目录 时间复杂度的定义时间复杂度的分类时间复杂度分析常见数据结构和算法的时间复杂度常见数据结构常见算法 常见排序算法说明冒泡排序(Bubble Sort)快速排序(Quick Sort)归并排序(Merge Sort)堆排序(Heap Sort) 时间复杂度的定义 时间复杂度就是一种用来描述算法在输入规…

centos搭建activemq5.16

下载jdk、activemq&#xff08;我这里都放在在/usr/local&#xff09;之后。。。 在/usr/local/activemq/bin/目录下有一个env文件添加JAVA_HOME 注意activemq.xml里面不能出现中文&#xff0c;注释也不行 接下来在/usr/lib/systemd/system/创建activemq.service文件 # 单元节…

天选之子C++是如何发展起来的?如何学习C++呢?

天选之子C是如何发展起来的&#xff1f;如何学习C呢? 一、什么是C二、C发展史三、C的重要性3.1 语言的使用广泛度3.2 在工作领域 四、如何学习C4.1 大佬怎么学&#xff1f;4.2 自己怎么学 一、什么是C C语言是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复…

【LeetCode-中等题】107. 二叉树的层序遍历 II

文章目录 题目方法一&#xff1a;队列层序迭代 题目 方法一&#xff1a;队列层序迭代 解题详情&#xff1a;【LeetCode-中等题】102. 二叉树的层序遍历 res.add(0,zres); //效果是将 zres 列表作为 res 的第一个子列表&#xff0c;并将其它原本在第一位置及之后的子列表向后移…

1979-2021年地级市空气流通系数数据

1979-2021年地级市空气流通系数数据 1、时间&#xff1a;1979-2021年 2、来源&#xff1a;整理自era-interim 3、范围&#xff1a;367个地级市 4、指标&#xff1a;10米风速、边界层高度、空气流通系数 5、指标解释&#xff1a; 空气流动系数是空气污染的常用工具变量&am…

音视频转换器 Permute 3 for mac中文

Permute 3是一款界面简洁且易于使用的媒体文件格式转换器。它具有强大的转换功能&#xff0c;无需复杂的配置&#xff0c;只需将文件拖放到界面窗口&#xff0c;就能进行媒体转换&#xff0c;非常方便。 Permute 3支持视频、音乐和图像的格式转换&#xff0c;可以通过拖拽支持…

Jetpack Compose基础组件 - Image

Image的源码参数预览 Composable fun Image(painter: Painter,contentDescription: String?,modifier: Modifier Modifier,alignment: Alignment Alignment.Center,contentScale: ContentScale ContentScale.Fit,alpha: Float DefaultAlpha,colorFilter: ColorFilter? …

个人记录--跟着同门学c#

前提&#xff1a;已安装Visual Studio ArcEngine&DotSpatial C#二次开发&#xff08;一&#xff09;之DotSpatial使用心得记录_dotspatial 开发文档_只想敲代码的研究僧的博客-CSDN博客 ArcEngine是一种用于二次开发的软件开发工具包&#xff0c;可以用来创建基于ArcGIS…

深入分析ASEMI代理的瑞萨R5F5210BBDFB#10芯片

编辑-Z 随着科技发展的不断升级&#xff0c;电子技术正变得越来越复杂。不过&#xff0c;在这个繁复的电子世界中&#xff0c;有一样东西在不断地帮助着我们简化各种复杂的任务&#xff0c;那就是微型集成电路&#xff0c;也叫做“芯片”。今天我们将会对R5F5210BBDFB#10芯片这…

改变世界的物理学方程

1.牛顿万有引力定律 艾萨克牛顿爵士的万有引力定律&#xff0c;通常简称为牛顿万有引力定律&#xff0c;是物理学的基本原理。牛顿于 1687 年在其开创性著作《Philosophi Naturalis Principia Mathematica》&#xff08;自然哲学的数学原理&#xff09;中发表了这一定律。 该定…

6个免费视频素材网站,高清无水印,赶紧收藏起来~

6个免费视频素材网站&#xff0c;高清无水印&#xff0c;赶紧收藏起来~ 1、菜鸟图库 https://www.sucai999.com/video.html?vNTYxMjky 菜鸟图库网素材非常丰富&#xff0c;网站主要还是以设计类素材为主&#xff0c;高清视频素材也很多&#xff0c;像风景、植物、动物、人物、…

使用 PyTorch 的计算机视觉简介 (1/6)

一、说明 Computer Vision&#xff08;CV&#xff09;是一个研究计算机如何从数字图像和/或视频中获得一定程度的理解的领域。理解这个定义具有相当广泛的含义 - 它可以从能够区分图片上的猫和狗&#xff0c;到更复杂的任务&#xff0c;例如用自然语言描述图像。 二、CV常见的问…

提升网站效率与SEO优化:ZBlog插件集成解决方案

在创建和管理网站的过程中&#xff0c;使用合适的工具和插件可以大幅提升效率&#xff0c;并改善搜索引擎优化&#xff08;SEO&#xff09;结果。ZBlog插件是为ZBlogCMS设计的一组工具&#xff0c;它们帮助网站管理员轻松地满足各种需求&#xff0c;从采集内容到发布、推送和SE…

基于dq0变换的三相并联有源电力滤波器模拟模型(Simulink)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…