LeetCode 热题 100之普通数组

1.最大子数组和

在这里插入图片描述
思路分析:这个问题可以通过动态规划来解决,我们可以使用Kadane’s Algorithm(卡登算法)来找到具有最大和的连续子数组。

  • Kadane’s Algorithm 的核心思想是利用一个变量存储当前的累加和 currentSum,并通过每次与之前的最大子数组和 maxSum 比较,更新 maxSum。它在遍历过程中不断累加子数组的和,但一旦累加和变为负数时,放弃当前累加,从下一个元素重新开始累加。这样确保了子数组和始终是最大的。

  • 初始化:将 maxSum 和 currentSum 初始化为数组的第一个元素,即 nums[0]

  • 遍历数组

    • 从第二个元素开始,逐个元素检查累加currentSum;
      • currentSum = max(nums[i], currentSum + nums[i]):选择当前元素或当前累加和加上当前元素两者中的较大值。
      • 如果 currentSum 大于 maxSum,则更新 maxSum。
  • 返回结果:遍历完成后,maxSum 即为最大子数组的和。

具体实现代码(详解版):

class Solution {
public:
    int maxSubArray(std::vector<int>& nums) {
        int maxSum = nums[0];       // 初始化 maxSum 为数组第一个元素,用于存储最大子数组的和
        int currentSum = nums[0];    // 初始化 currentSum 为数组第一个元素,用于当前子数组的累加和
        
        // 遍历数组,从第二个元素开始(因为第一个元素已经初始化了)
        for (int i = 1; i < nums.size(); i++) {
            // 更新 currentSum,将当前元素和 currentSum + 当前元素 取较大值
            // 如果 currentSum + nums[i] 比 nums[i] 小,说明重新开始一个新的子数组会更大
            currentSum = max(nums[i], currentSum + nums[i]);

            // 更新 maxSum,存储最大子数组的和
            maxSum = max(maxSum, currentSum);
        }
        
        // 返回最大子数组的和
        return maxSum;
    }
};

2.合并区间

在这里插入图片描述
思路分析1(Acwing板子)
算法基础课-区间合并

具体实现代码(详解版):

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        vector<vector<int>> res;  // 用于存放合并后的区间结果
        sort(intervals.begin(), intervals.end());  // 按区间起点升序排序

        // 初始化st和ed为一个极小的值,用于在第一次遍历时识别有效区间
        int st = -2e9, ed = -2e9;

        // 遍历所有区间
        for (int i = 0; i < intervals.size(); i++) {
            // 如果当前区间的起点大于当前的结束位置,则无重叠
            if (ed < intervals[i][0]) {
                // 如果是有效区间,将前一个区间加入结果中
                if (st != -2e9) res.push_back({st, ed});
                // 更新st和ed为当前区间的起点和终点
                st = intervals[i][0];
                ed = intervals[i][1];
            } else {
                // 当前区间与前一个区间重叠,合并区间
                ed = max(ed, intervals[i][1]);
            }
        }
        // 添加最后一个区间到结果中
        if (st != -2e9) res.push_back({st, ed});

        return res;
    }
};

思路分析2:直接遍历区间数组,判断是否有重叠。

具体实现代码(详解版):

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        // 按区间的起始位置排序
        sort(intervals.begin(), intervals.end());
        
        // 用于存放合并后的结果
        vector<vector<int>> res;
        
        // 遍历区间数组
        for (const auto& interval : intervals) {
            // 如果结果数组为空或当前区间不与最后一个区间重叠,直接加入
            if (res.empty() || res.back()[1] < interval[0]) {
                res.push_back(interval);
            } else {
                // 否则,有重叠,更新最后一个区间的终点
                res.back()[1] = max(res.back()[1], interval[1]);
            }
        }
        
        return res;
    }
};

3.轮转数组

在这里插入图片描述
思路分析1:将后面k个元素和前面n-k个元素添加到res中即可。要注意k = k % n

具体实现代码(详解版):

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int n = nums.size();
        k = k % n;  // 如果 k 大于数组长度,取余数来简化操作
        vector<int> res;

        // 将最后 k 个元素加入结果中
        for (int i = n - k; i < n; ++i) 
            res.push_back(nums[i]);

        // 然后把前 n - k 个元素加在结果后面
        for (int i = 0; i < n - k; ++i) 
            res.push_back(nums[i]);

        // 将旋转后的结果更新到原数组
        nums = res;
    }
};

思路分析2:直接进行反转,先整体反转,再将将前 k 个元素反转,再将剩余的 n-k 个元素反转
具体实现代码(详解版):

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int n = nums.size();
        k = k % n;  // 计算实际旋转步数,防止 k 超出数组长度
        reverse(nums.begin(), nums.end());  // 1. 反转整个数组
        reverse(nums.begin(), nums.begin() + k);  // 2. 反转前 k 个元素
        reverse(nums.begin() + k, nums.end());  // 3. 反转剩余的 n-k 个元素
    }
};

在这里插入图片描述
很明显第二种方法更优!太快了!

4.除自身以外数组的乘积

在这里插入图片描述
思路分析:使用两个数组:一个数组存储每个元素左侧所有元素的乘积,另一个数组存储每个元素右侧所有元素的乘积。通过将这两个数组的对应元素相乘,得到每个位置的最终结果。

  • 初始化answer 数组初始化为 1,因为乘法的单位是 1
  • 左侧乘积
    • 我们使用一个变量 left_product 来存储当前元素左侧的乘积。
    • 对于每个元素 nums[i],我们将 left_product 的值赋给 answer[i],这表示在位置 i 的左侧乘积
    • 然后,更新 left_product,将 nums[i] 的值乘入,准备计算下一个位置。
  • 右侧乘积:我们继续使用之前的 answer 数组,它现在包含了每个元素左侧的乘积。接下来,我们将计算每个元素右侧的乘积。
    • 使用一个变量 right_product 来存储当前元素右侧的乘积,并将其初始化为 1。
    • 反向遍历
      • 对于每个元素 nums[i],将 right_product 的值乘入 answer[i],这样 answer[i] 就等于左侧乘积乘以右侧乘积
      • 更新 right_product,将 nums[i] 的值乘入,准备计算下一个位置。

具体实现代码(详解版):

class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        int n = nums.size();
        vector<int> answer(n, 1); // 初始化结果数组为 1

        // 1. 计算左侧的乘积
        int left_product = 1; // 初始化左侧乘积
        for (int i = 0; i < n; i++) {
            answer[i] = left_product; // 设置 answer[i] 为左侧乘积
            left_product *= nums[i];   // 更新左侧乘积
        }

        // 2. 计算右侧的乘积并更新结果
        int right_product = 1; // 初始化右侧乘积
        for (int i = n - 1; i >= 0; i--) {
            answer[i] *= right_product; // 将右侧乘积乘以之前的结果
            right_product *= nums[i];    // 更新右侧乘积
        }

        return answer; // 返回最终结果
    }
};

另一种写法:

class Solution {
public:
    vector<int> productExceptSelf(vector<int>& nums) {
        int n = nums.size();
        vector<int> answer(n, 1); // 初始化结果数组

        // 计算左侧乘积
        for (int i = 1; i < n; ++i) {
            answer[i] = answer[i - 1] * nums[i - 1];
        }

        // 计算右侧乘积并更新 answer
        int right_product = 1;
        for (int i = n - 1; i >= 0; --i) {
            answer[i] *= right_product; // 将右侧乘积乘入结果
            right_product *= nums[i];   // 更新右侧乘积
        }

        return answer;
    }
};

还有这种双指针的做法,也是大为简洁!值得借鉴!

std::vector<int> productExceptSelf2(std::vector<int>& nums) {
    std::vector<int> answer(nums.size(), 1); // 初始化输出数组
    int left = 0, right = nums.size() - 1; // 指针初始化
    int lp = 1, rp = 1; // 左侧乘积和右侧乘积

    // 双指针法
    while (right >= 0 && left < nums.size()) {
        answer[right] *= rp; // 更新右侧元素的乘积
        answer[left] *= lp; // 更新左侧元素的乘积
        lp *= nums[left++]; // 更新左侧乘积
        rp *= nums[right--]; // 更新右侧乘积
    }
    return answer; // 返回结果
}

5.缺失的第一个正数

在这里插入图片描述
思路分析:要在时间复杂度O(n) 和常数级空间复杂度下找到未排序数组 nums 中最小的缺失正整数,我们可以采用原地哈希(或称为置换排序)的方式。具体思路如下:

  • 目标:我们的目标是将每个正整数 x 放置在下标 x - 1 的位置上(例如,数字 1 应该放在下标 0 的位置,数字 2 应该放在下标 1,依此类推)。这样,如果数组中有数字 1, 2, …, n,它们都会出现在各自对应的位置上。
  • 交换过程
    • 遍历数组,如果nums[i]在[1,n]范围内,并且nums[i] != nums[nums[i] - 1],则将nums[i]放到其正确的位置num[i] -1。通过交换的方式来调整位置。
    • 不断重复交换,直至当前位置的数字被放到了正确的位置为止。此过程会在 O ( n ) O(n) O(n)时间内完成,因为每个元素最多只会被交换一次
  • 查找缺失的正整数
    • 再次遍历数组,找到第一个位置i,使得nums[i] != i + 1,此时i + 1就是我们要找的最小的缺失正整数
    • 如果所有位置都满足nums[i] == i + 1,那么数组中的所有正整数[1,n]都出现过,即最小缺失正整数为n + 1.

一个结论:不论数组 nums 是什么内容,数组长度为 N 时,最小缺失的正整数一定落在 [1, N+1]
这个范围内。这就是为什么算法中只需要关注 [1, N+1],而无需遍历其他更大的数字的原因。

具体实现代码(详解版):

class Solution {
public:
    int firstMissingPositive(vector<int>& nums) {
        int n = nums.size();
        //将每个数放到对应的位置
        for(int i = 0 ; i < n ; i ++){
            while(nums[i] > 0 && nums[i] <= n
             && nums[i] != nums[nums[i] - 1] ){
                swap(nums[i],nums[nums[i] - 1]);
             }
        }
        //查找第一个位置i,使得nums[i] != i + 1
        for(int i = 0; i < n ; i ++){
            if(nums[i] != i + 1){
                return i + 1;
            }
        }
        //如果所有位置都正确,则返回 n + 1
        return n + 1;
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【高中生讲机器学习】22. 信息论基础:信息熵、交叉熵、相对熵

创建时间&#xff1a;2024-10-16 首发时间&#xff1a;2024-10-24 最后编辑时间&#xff1a;2024-10-24 作者&#xff1a;Geeker_LStar FIRST OF ALL!!! 2024.10.24&#xff01;&#xff01; 1024 快乐&#xff01;&#xff01;&#xff01; 你好呀~这里是 Geeker_LStar 的人工…

IDEA初探:深入理解 Structure 功能

一、Structure - 类视图 Structure 是 IDEA 中的一个视图工具&#xff0c;它提供了对当前文件中结构元素的快速访问。通过 Structure&#xff0c;我们可以方便地查看和导航到代码中的各个部分&#xff0c;从而提高代码编辑和浏览的效率。 1.1 基本概念 Structure 视图以树形结…

Spring Boot:植物健康监测的智能先锋

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了植物健康系统的开发全过程。通过分析植物健康系统管理的不足&#xff0c;创建了一个计算机管理植物健康系统的方案。文章介绍了植物健康系统的系统分析部分&…

一文带你搞懂RabbitMQ 如何保证消息不丢失

RabbitMQ使用场景&#xff1a; 异步发送&#xff08;验证码、短信、邮件&#xff09;MySQL和Redis&#xff0c;ES之间的数据同步分布式事务削峰填谷 什么情况下消息容易丢失&#xff1a; 消息未到达交换机消息未到达队列队列中消息丢失消费者未接收到消息 解决消息丢失的方法…

python查询并安装项目所依赖的所有包

引言 如果需要进行代码的移植&#xff0c;肯定少不了在另一台pc或者服务器上进行环境的搭建&#xff0c;那么首先是要知道在已有的工程的代码中用到了哪些包&#xff0c;此时&#xff0c;如果是用人工去一个一个的代码文件中去查看调用了哪些包&#xff0c;这个工作甚是繁琐。…

js面试问题笔记(一)

一.热门js面试 1.简述同步和异步的区别? 同步: 浏览器访问服务器请求,用户看到页面刷新 ,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,进行下一步操作 异步: 浏览器访问服务器请求,用户正常操作,浏览器后端进行请求,等请求完,页面不刷新,新内容也会出现,用户看到…

【HarmonyOS Next】原生沉浸式界面

背景 在实际项目中&#xff0c;为了软件使用整体色调看起来统一&#xff0c;一般顶部和底部的颜色需要铺满整个手机屏幕。因此&#xff0c;这篇帖子是介绍设置的方法&#xff0c;也是应用沉浸式效果。如下图&#xff1a;底部的绿色延伸到上面的状态栏和下面的导航栏 UI 在鸿蒙…

Grid View 网格视图

GoTo DevExpress Data Grid 数据网格 Grid View 网格视图 GridView 是默认的数据网格视图&#xff0c;它以传统的表格格式显示数据。View 将数据源记录呈现为行&#xff0c;将数据源字段呈现为列。数据值显示在各个单元格中。 以下文档包含有关此表格布局的主要元素的深入信…

多线程——线程安全的集合类

目录 前言 一、多线程环境使用 ArrayList 1.进行加锁 2.使用 SynchronizedList 类 3.使用 CopyOnWriteArrayList 类 二、多线程环境使用队列 1.进行加锁 2.使用阻塞队列 三、多线程环境使用哈希表 1.Hashtable 2.ConcurrentHashMap &#xff08;1&#xff09;缩小锁…

vue文件转AST,并恢复成vue文件(适用于antdv版本升级)

vue文件转AST&#xff0c;并恢复成vue文件---antdvV3升级V4 vue文件转AST&#xff0c;重新转回原文件过程如何获取项目路径读取项目文件&#xff0c;判断文件类型分别获取vue文件 template js&#xff08;vue2和vue3&#xff09;处理vue 文件template部分处理vue script部分uti…

【线下+线上会议|国内外双会场】2024年第四届数字化社会与智能系统国际学术会议(DSInS 2024)-悉尼/郑州双会场

2024年第四届数字化社会与智能系统国际学术会议&#xff08;DSInS 2024&#xff09;-悉尼/郑州双会场 2024 4th International Conference on Digital Society and Intelligent Systems 会议官网&#xff1a;www.dsins.org 2024 4th International Conference on Digital Soc…

龙迅#LT89101 适用于 MIPI DSI/CSI摄像头和 LVDS 中继信号延长功能,分辨率可支持 1080P@60HZ!

1. 描述 Lontium LT89101 是一款高性能 MIPI DSI/CSI-2 和 LVDS 中继器&#xff0c;用于汽车系统应用的移动显示或摄像头信号整形。 LT89101采用先进的 CMOS 工艺制造&#xff0c;并采用小外形 7.5mm x 7.5mm QFN64 封装。该封装符合 RoHS 标准&#xff0c;额定工作温度范围为 …

MySQL8.0.40编译安装

近期MySQL发布了8.0.40版本&#xff0c;与之前的版本相比&#xff0c;部分依赖包发生了变化&#xff0c;因此重新编译一版&#xff0c;也便于大家参考。 1. 下载源码 选择对应的版本、选择源码、操作系统 如果没有登录或者没有MySQL官网账号&#xff0c;可以选择只下载 2. 进…

element 按钮变形 el-button样式异常

什么都没动&#xff0c;element UI的按钮变形了&#xff0c;莫名其妙&#xff0c;连官网的也变形了&#xff0c;换了其它浏览器又正常&#xff0c; 难道这是element UI的问题&#xff1f;NO&#xff0c;是浏览器的插件影响到了&#xff01;去扩展插件里面一个个关闭扩展&#x…

MySql中的锁的分类

锁的分类 MySQL锁可以按模式分类为&#xff1a;乐观锁与悲观锁。按粒度分可以分为全局锁、表级锁、页级锁、行级锁。按属性可以分为&#xff1a;共享锁、排它锁。按状态分为&#xff1a;意向共享锁、意向排它锁。按算法分为&#xff1a;间隙锁、临键锁、记录锁。 二、全局锁、表…

ClickHouse与各种组件的关系

ClickHouse和其他组件关系如下&#xff1a; Flink支持ClickHouse Sink支持Hive/SparkSQL数据批量导入ClickHouseHetuEngine支持ClickHouse数据源常用第三方工具如DBeaver支持ClickHouse对接ClickHouse依赖ZooKeeper实现了分布式DDL执行以及ReplicatedMergeTree表主备节点之间的…

多线程—— JUC 的常见类

目录 前言 一、Callable 接口 1.Callable 介绍 2.代码示例 3.创建线程的方式 二、ReentrantLock 类 1.ReentrantLock 介绍 2.代码示例 3.与 synchronized 的区别 三、信号量 Semaphore 类 1.Semaphore 介绍 2.代码示例 3.保证线程安全的方式 四、CountDownLatch …

二、Spring的执行流程

文章目录 1. spring的初始化过程1.1 ClassPathXmlApplicationContext的构造方法1.2 refresh方法&#xff08;核心流程&#xff09;1.2.1 prepareRefresh() 方法1.2.2 obtainFreshBeanFactory() 方法1.2.3 prepareBeanFactory() 方法1.2.4 invokeBeanFactoryPostProcessors() 方…

(linux驱动学习 - 12). IIC 驱动实验

目录 一.IIC 总线驱动相关结构体与函数 1.i2c_adapter 结构体 2.i2c_algorithm 结构体 3.向系统注册设置好的 i2c_adapter 结构体 - i2c_add_adapter 4.向系统注册设置好的 i2c_adapter 结构体 - i2c_add_numbered_adapter 5.删除 I2C 适配器 - i2c_del_adapter 二.IIC 设…

【C++算法】11.滑动窗口_最大连续1的个数lll

文章目录 题目链接&#xff1a;题目描述&#xff1a;解法C 算法代码&#xff1a;图解 题目链接&#xff1a; 1004. 最大连续 1 的个数 III 题目描述&#xff1a; 解法 解法一&#xff1a;暴力枚举zero计数器 转化找出最长的子数组&#xff0c;0的个数不超过k个。 例如&#xf…