JAVA刷题之数组的总结和思路分享

news2025/1/11 0:16:08

꒰˃͈꒵˂͈꒱ write in front ꒰˃͈꒵˂͈꒱
ʕ̯•͡˔•̯᷅ʔ大家好,我是xiaoxie.希望你看完之后,有不足之处请多多谅解,让我们一起共同进步૮₍❀ᴗ͈ . ᴗ͈ აxiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客
本文由xiaoxieʕ̯•͡˔•̯᷅ʔ 原创 CSDN 如需转载还请通知˶⍤⃝˶
个人主页:xiaoxieʕ̯•͡˔•̯᷅ʔ—CSDN博客
系列专栏:xiaoxie的刷题系列专栏——CSDN博客●'ᴗ'σσணღ*
我的目标:"团团等我💪( ◡̀_◡́ ҂)" 

( ⸝⸝⸝›ᴥ‹⸝⸝⸝ )欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​+关注(互三必回)! 

beb57f2cc888447ab7e8bbdd4bb1bc08.png

数组篇 

1. 在排序数组中查找元素的第一个和最后一个位置

力扣链接

d1c87083f7bd4365a26e4484ba53a714.png

 我相信大家一看到这题是有序的数组,有点基础的同学们都会想到二分查找法,这一题有思路很容易,但提交时却老是无法通过,这就是因为没有考虑好边界问题了,现在博主为大家介绍两种二分查找法

1.普通二分查找法

做好这一题的关键就在于找到边界

题就是查找 target 在 nums 中的区间,即查找 target 在 nums 中的左右边界。

仔细想的话,要找 target 在 nums 数组中的左右边界,无非存在 3 种情况:

target 在 nums[0] ~ nums[n-1] 中,nums 中存在 target。例如 nums = [5,7,7,8,8,10],target = 8,返回 [3,4]。
target 在 nums[0] ~ nums[n-1] 中,nums 中不存在 target。例如 nums = [5,7,7,8,8,10],target = 6,返回 [-1,-1]。
target < nums[0] 或者 target > nums[n-1]。例如 nums = [5,7,7,8,8,10], target = 4,返回 [-1,-1]。

用两个二分查找,一个二分查找查找左边界,另一个查找右边界,分情况讨论上述的 3 种情况。


class Solution {
    public int[] searchRange(int[] nums, int target) {
        int start = lowerBound(nums, target);
        if (start == nums.length || nums[start] != target)
            return new int[]{-1, -1};
        // 如果 start 存在,那么 end 必定存在
        int end = lowerBound(nums, target + 1) - 1;
        return new int[]{start, end};
    }

    private int lowerBound(int[] nums, int target) {
        int left = 0, right = nums.length - 1; // 闭区间 [left, right]
        while (left <= right) { // 区间不为空
            int mid = left + (right - left) / 2;
            if (nums[mid] < target)
                left = mid + 1; // 范围缩小到 [mid+1, right]
            else
                right = mid - 1; // 范围缩小到 [left, mid-1]
        }
        return left; // right+1
    }

2.红蓝二分查找法

相信大家一直对二分查找法的边界问题一直有困扰,一般来说二分查找就这些东西,在边界和细节上搞人,只要每次做题小心点,就没啥问题。现在博主就为大家介绍另外一种二分查找方法,它不需要考虑那么多问题,只要在最后返回值时多多注意就好了

class Solution {
    public int searchRangeLeft(int[] nums, int target) {
        int left = -1;
        int right = nums.length;
        while (left + 1 != right) {
            int mid = (left + right) / 2;
            if (nums[mid] <= target) {
                left = mid;
            } else {
                right = mid;
            }
        }
        return left;
    }
    
    public int searchRangeRight(int[] nums, int target) {
        int left = -1;
        int right = nums.length;
        while (left + 1 != right) {
            int mid = (left + right) / 2;
            if (nums[mid] < target) {
                left = mid;
            } else {
                right = mid;
            }
        }
        return right;
    }
    public int[] searchRange(int[] nums, int target) {
        int leftIndex = searchRangeLeft(nums, target);
        int rightIndex = searchRangeRight(nums, target);
        if (leftIndex >= rightIndex && leftIndex < nums.length && nums[leftIndex] == target && nums[rightIndex] == target) {
            return new int[] {rightIndex, leftIndex};
        }
        return new int[] {-1, -1};
    }
}

开始时,L指针和 R指针取在搜索区间界外,L=首个元素下标−1,R=末尾元素下标+1,此时所有元素均未着色;
循环条件始终为 L+1 < R,当 L=R 时跳出循环,此时蓝红区域划分完成,所有元素均已着色;
M指针取值始终为 M =(L+R)/2
L指针和 R指针变化的时候直接变为 M指针,即对 M 指针所指向元素进行染色,无需 +1 或者−1;
本模板唯一变化的地方是判断目标元素最终落在左边蓝色区域还是右边红色区域。以不变应万变,根据情况的不同,变换判断条件,大大的降低了出错的可能。

bd82c988822748eb88c81136a103413c.png

98fe462e031541f68718b4eb0b29a65f.png

 这样就找到左下标和右下标啦,再因为该题是找不到就返回-1,所以还要再判断,同时红蓝二分查找法并不只是适用于这题哦,它在大部分的题目都适用,目前博主还没有遇到不适用的情况,所以大家可以放心用,在变换判断条件时和普通二分查找法,大大的降低了出错的可能。

2. 删除有序数组中的重复项---快慢指针

d069c12c176c4d1c9b7d7e3a4d3fb6a3.png

这是力扣上的一道简单题,有的同学可能说了,多余的元素,删掉不就得了。

要知道数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖,所以从中我们第一时间想到也是最简单的就是暴力解法

1.暴力解法

这个题目暴力的解法就是两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组。

public int removeDuplicates(int[] nums) {
    if (nums.length == 0) {
        return 0;
    }
    int k = 1; // 记录唯一元素的个数
    for (int i = 1; i < nums.length; i++) {
        boolean isDuplicate = false;
        // 检查当前元素是否已经存在于前面的唯一元素中
        for (int j = 0; j < k; j++) {
            if (nums[i] == nums[j]) {
                isDuplicate = true;
                break;
            }
        }
        // 如果当前元素是新的唯一元素,则加入到唯一元素列表中
        if (!isDuplicate) {
            nums[k] = nums[i];
            k++;
        }
    }
    return k;
}

 很明显暴力解法的时间复杂度是O(n^2),这道题目暴力解法在leetcode上是可以过的。但这面试中你写这个解法,显然是不能让面试官满意的。博主这有一个使用双指针,快慢指针的解法

2.快慢指针

双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

定义快慢指针

  • 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
  • 慢指针:指向更新 新数组下标的位置

很多同学这道题目做的很懵,就是不理解 快慢指针究竟都是什么含义,所以一定要明确含义,后面的思路就更容易理解了。要解这题的思路如下

首先我们写记录下数组第一个元素的数值:

 int val = nums[0];

然后我们在定义一个快指针和慢指针,指向数组第二个元素:然后快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组;慢指针:指向更新 新数组下标的位置,如下图:

025a42c81a934713a2391590433fd070.png

public int removeDuplicates(int[] nums) {
    int val = nums[0]; // 记录当前唯一元素的值
    int slow = 1; // 慢指针,指向下一个唯一元素应该存放的位置
    for (int fast = 1; fast < nums.length; fast++) {
        if (nums[fast] != val) { // 如果当前元素与前一个唯一元素不相同
            nums[slow] = nums[fast]; // 将当前元素存放到慢指针指向的位置
            val = nums[slow]; // 更新当前唯一元素的值
            slow++; // 慢指针向后移动
        }
    }
    return slow; // 返回唯一元素的个数
}

双指针法(快慢指针法)在数组和链表的操作中是非常常见的,很多考察数组、链表、字符串等操作的面试题,都使用双指针法,写成这样你的代码才可以说达到了面试的高度了,所以我们遇到这一类的题型可以多往快慢指针法那边靠靠,我相信你多练习,多学习,一定可以做到更好。

3.长度最小的子数组

6f80fdd3692b4c0c87c4b07783195d1b.png

 这是力扣上的一道中等难度的数组题,还是一样看到这一题,第一个想到的方法就是用两个for 循环的暴力解法

1.暴力解法

public class Solution {
    public int minSubArrayLen(int s, int[] nums) {
        int result = Integer.MAX_VALUE; // 最终的结果
        int sum = 0; // 子序列的数值之和
        int subLength = 0; // 子序列的长度
        for (int i = 0; i < nums.length; i++) { // 设置子序列起点为i
            sum = 0;
            for (int j = i; j < nums.length; j++) { // 设置子序列终止位置为j
                sum += nums[j];
                if (sum >= s) { // 一旦发现子序列和超过了s,更新result
                    subLength = j - i + 1; // 取子序列的长度
                    result = result < subLength ? result : subLength;
                    break; // 因为我们是找符合条件最短的子序列,所以一旦符合条件就break
                }
            }
        }
        // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
        return result == Integer.MAX_VALUE ? 0 : result;
    }
}

2.滑动窗口

该如何把两个for循环变成一个呢,我想大家想到的一定是双指针,对没错,使用双指针,现在博主来为大家介绍一种双指针方法,滑动窗口。所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。它一样是使用双指针,只不过这种解法更像是一个窗口的移动,所以就称为滑动窗口。

在本题中实现滑动窗口,主要确定如下三点:

  • 窗口内是什么?
  • 如何移动窗口的起始位置?
  • 如何移动窗口的结束位置?

窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。

窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。

窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,也就是for循环里的索引。

解题的关键在于 窗口的起始位置如何移动,如图所示:

760367123a294e95b5d6ff8488933fa3.png

代码如下:

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int result = Integer.MAX_VALUE;
        int star = 0,end = 0;
         int sum = 0;
        for(;end < nums.length; end++) {
            sum += nums[end];
            while(sum >= target) {
                int subl = end - star+1;
                result = Math.min(subl,result);//动态更新数值
                sum -= nums[star++];
            } 
        }
        return result == Integer.MAX_VALUE ? 0 : result;
    }
}

好了这就是数组篇的全部内容了,后续博主还会持续更新,链表篇等等内容,大家可以点个关注,不错过后续精彩内容。感谢您的阅读,祝您一天生活愉快 

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

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

相关文章

荔枝FM语音批量下载

动机 最近想下载一下自己在蜻蜓FM上上传的音频&#xff0c;发现不支持批量下载。于是去找了一些下载器&#xff0c;万万没想到&#xff0c;该下载器只能下载前十条&#xff0c;再下要注册&#xff0c;注册费5元。尼玛&#xff0c;不能忍。本来就不是太难的技术&#xff0c;还搞…

HarmonyOS应用开发——页面

我们将对于多页面以及更多有趣的功能展开叙述&#xff0c;这次我们对于 HarmonyOS 的很多有趣常用组件并引出一些其他概念以及解决方案、页面跳转传值、生命周期、启动模式&#xff08;UiAbility&#xff09;&#xff0c;样式的书写、状态管理以及动画等方面进行探讨 页面之间…

探索Python的神奇力量:详解setattr函数的使用教程

概要&#xff1a; 在Python这个强大而灵活的编程语言中&#xff0c;有许多函数可以帮助开发者实现各种各样的任务。其中一个非常有用且功能强大的函数是setattr函数。setattr函数允许我们在运行时动态地设置对象的属性值&#xff0c;这为我们的代码增加了灵活性和扩展性。本文…

mvc模式test

项目结构 Book.java package beans; public class Book {private Integer id;private String name;private double price;public Integer getId() {return id;}public void setId(Integer id) {this.id id;}public String getName() {return name;}public void setName(Strin…

申请SSL证书的步骤

一&#xff1a;首先确定自己所需要的证书类型 1&#xff1a;小微企业以及个人网站选择免费的DV证书是完全够用的。 2&#xff1a;中大型企业尤其是涉及到需要用户填写账户密码的建议OV及以上的证书。 3&#xff1a;根据适配范围确认需要的是单域名&#xff0c;多域名&#xff0…

python安装与配置:在centos上使用shell脚本一键安装

介绍 Python是一种功能强大且广泛使用的编程语言&#xff0c;但在某些情况下&#xff0c;您可能需要安装和配置特定版本的Python。本教程将向您展示如何使用一个Shell脚本自动完成这个过程&#xff0c;以便您可以快速开始使用Python 3。 使用shell自动化安装教程 1. 复制脚本…

java:spring-boot-starter-actuator的使用

简介 Spring Boot Actuator 是 Spring Boot 提供的一个功能强大的模块&#xff0c;用于监控和管理您的应用程序。它为开发人员和运维团队提供了许多有用的端点&#xff0c;用于获取有关应用程序运行时状态的信息。 什么是端点&#xff1f; "端点"是指提供了某种功能…

C++作业6

以下是一个简单的比喻&#xff0c;将多态概念与生活中的实际情况相联系&#xff1a; 比喻&#xff1a;动物园的讲解员和动物表演 想象一下你去了一家动物园&#xff0c;看到了许多不同种类的动物&#xff0c;如狮子、大象、猴子等。现在&#xff0c;动物园里有一位讲解员&…

关于对Spring事件监听机制相关解析

1、Spring事件监听器使用 Spring事件监听体系包括三个组件&#xff1a;事件、事件监听器&#xff0c;事件广播器 事件&#xff1a;定义事件类型和事件源&#xff0c;需要继承ApplicationEvent import org.springframework.context.ApplicationEvent; public class OrderEvent…

springcloud智慧工地管理平台源码(工程全生命周期管理)

智慧工地采用全新的工程全生命周期管理理念&#xff0c;以物联网技术为核心&#xff0c;利用传感网络、远程视频监控、物联网、云计算等新型技术&#xff0c;依托移动和固定宽带网络&#xff0c;围绕施工过程管理&#xff0c;建造互联协同、智能生产、科学管理的信息化生态圈&a…

Python源码分享10:使用海龟画图turtle画哆啦A梦

turtle模块是一个Python的标准库之一&#xff0c;它提供了一个基于Turtle graphics的绘图库。Turtle graphics是一种流行的绘图方式&#xff0c;它通过控制一个小海龟在屏幕上移动来绘制图形。 turtle模块可以让您轻松地创建和控制海龟图形&#xff0c;从而帮助您学习Python编…

虚拟网络技术:bond技术

网卡bond也称为网卡捆绑&#xff0c;就是将两个或者更多的物理网卡绑定成一个虚拟网卡。 bond的作用&#xff1a; 1.提高网卡的吞吐量 2.增加网络的高可用&#xff0c;实现负载均衡。 一、bond简介 bond技术即bonding&#xff0c;能将多块物理网卡绑定到一块虚拟网卡上&…

AMEYA360--罗姆与Quanmatic公司利用量子技术优化制造工序并完成验证

全球知名半导体制造商罗姆(总部位于日本京都市)于2023年1月起与 Quanmatic Inc.(总部位于日本东京都新宿区&#xff0c;以下简称“Quanmatic”)展开合作&#xff0c;在半导体制造工序之一的EDS工序中测试并引入量子技术&#xff0c;以优化制造工序中的组合。目前&#xff0c;双…

springMVC实验(五)——数据校验

【知识要点】 数据校验的概念 在软件开发过程中&#xff0c;数据校验是非常重要的环节&#xff0c;用于确保数据的有效性和完整性 。数据校验分为客户端验证和服务端验证&#xff0c;客户端验证是确保人机交互过程中用户操作表单过程中的误操作&#xff0c;由JavaScript代码完…

Geoserver发布2000坐标系遇到的问题总结

在Geoserver上发布2000坐标系的服务时&#xff0c;要想正常发布服务&#xff0c;不仅仅是要涉及2000坐标系&#xff0c;还需要在发布的时候选择对坐标系。具体问题描述如下&#xff1a; 1.问题描述&#xff1a; 在发布好2000坐标系的服务后&#xff0c;在超图的平台加载服务时&…

联合基于信息论的安全和隐蔽通信的框架

这个标题很帅 abstractintroductionsystem modelPROPOSED JOINT OPTIMIZATION OF ITS AND COVERT TRANSMISSION RATE信息论安全 &#xff08;ITS&#xff09; Joint Information-Theoretic Secrecy and Covert Communication in the Presence of an Untrusted User and Warden …

根文件系统中文字符测试

一. 简介 本文在之前制作的根文件系统可以正常运行的基础上进行的&#xff0c;继上一篇文章地址如下&#xff1a; 根文件系统初步测试-CSDN博客 本文测试根文件系统的是否可以支持中文字符。 二. 根文件系统中文字符测试 1. 创建中文文件 打开 ubuntu虚拟机&#xff0c;进…

uniapp-hubildx配置

1.配置浏览器 &#xff08;1&#xff09;运行》运行到浏览器配置》配置web服务器 &#xff08;2&#xff09;选择浏览器安装路径 &#xff08;3&#xff09;浏览器安装路径&#xff1a; &#xff08;3.1&#xff09; 右键点击图标》属性 &#xff08;3.2&#xff09;选择目标&…

计算机组成原理-数据寻址-(相对寻址 基址寻址 变址寻址 )

文章目录 指令寻址vs数据寻址总览偏移寻址基址寻址基址寻址的作用变址寻址变址寻址的作用基址&变址复合寻址相对寻址相对寻址的作用 总结硬件如何实现数的比较 指令寻址vs数据寻址 总览 偏移寻址 变址寄存器&#xff1a;IX 基址寄存器&#xff1a;BR 基址寻址 没有基址…

EM32DX-C4【C#】站15

1外观&#xff1a; J301 直流 24V 电源输入 CAN0 CAN0 总线接口 CAN1 CAN1 总线接口 J201 IO 接线段子 S301-1、S301-2 输出口初始电平拨码设置 S301-3~S301-6 模块 CAN ID 站号拨码开关 S301-7 模块波特率拨码设置 S301-8 终端电阻选择开关 2DI&#xff1a; 公共端是…