【算法与数据结构】【数组篇】【题11-题15】

news2024/11/15 19:47:23

系列文章

本人系列文章-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/handsomethefirst/article/details/138226266?spm=1001.2014.3001.5502


1.数组基本知识点

1.1概念

数组就是一个集合。数组会用一些名为索引的数字来标识每项数据在数组中的位置,且在大多数编程语言中,索引是从 0 算起的。我们可以根据数组中的索引,快速访问数组中的元素。

数组中的元素在内存中是连续存储的,且每个元素占用相同大小的内存。

1.2 相关操作的时间复杂度和空间复杂度

访问元素时间复杂度都是O(1),空间复杂度O(1),因为对于固定大小的数组,访问时间不随数组大小而变化。通过下标可直接访问。

修改元素:时间复杂度O(1),空间复杂度O(1),与n无关,通过下标可直接修改

插入元素和删除元素:时间复杂度O(1),空间复杂度O(1),插入和删除元素都需要移动后面的元素,因此随n变化。

 题11 最大连续1的个数

给定一个二进制数组 nums , 计算其中最大连续 1 的个数。

示例 1:

输入:nums = [1,1,0,1,1,1]
输出:3
解释:开头的两位和最后的三位都是连续 1 ,所以最大连续 1 的个数是 3.

思路:
第一步:遍历数组,如果值等于1,则number加1,然后每次更新之前number中最大的那个
第二步:如果值不等于1,则重置number,开始重新计数。

 代码案例

class Solution
{
public:
    int findMaxConsecutiveOnes(vector<int> &nums)
    {
        int size = nums.size();
        int number = 0;
        int returnnumber = 0;

        for (int first = 0; first < size; first++)
        {

            if (nums[first] != 1) //如果值不是1,则重新记录数量
            {
                number = 0;
            }
            else 如果值是1,则数量+1
            {
                number++;
            }

            returnnumber = max(returnnumber, number);//每次更新最大连续数量的值
        }

        return returnnumber;
    }
};

题12 长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其总和大于等于 target 的长度最小的 子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例 2:

输入:target = 4, nums = [1,4,4]
输出:1

 思路:

首先需要查找子数组,所以不能排序此数组。因为需要找到子数组的头和尾部,思路可以靠近双指针。

第一次滑动:

第一次滑动达到目标 2+3+1+2=8

    2   3   1   2   4   3
    s             q

第一次尝试收缩发现 8-2< 7,则无法收缩。此时的长度为4,代表nums[0]满足条件的最小区间范围。


第2次滑动:

快指针继续向前,第二次达到目标 2+3+1+2+4=12

    2   3   1   2   4   3
                     q

第二次尝试收缩发现 10>7,可以收缩。

    2   3   1   2   4   3
         s             q

此时的长度也是4,代表nums[1]满足条件的最小区间范围。

再次尝试收缩, 7=7,可以收缩。

    2   3   1   2   4   3
              s        q

此时的长度是3,代表nums[2]满足条件的最小区间范围。

然后无法再次收缩了,此时nums[0],nums[1],nums[2]满足的最小区间范围。

第三次滑动:

快指针继续向前,第三次达到目标, 1+2+4+3>=7

    2   3   1   2   4   3
              s             q

然后尝试收缩,收缩成功, 10-1>=7

    2   3   1   2   4   3
                   s        q

此时的长度是3,代表nums[3]满足条件的最小区间范围。

然后继续尝试收缩,收缩成功,9-2=7

    2   3   1   2   4   3
                        s   q

此时的长度是2,代表nums[4]满足条件的最小区间范围。

此时quick走到了末尾,然后能收缩的都收缩了,代表nums[4]以后的都无法满足大于等于目标值的最小区间范围的条件。

代码案例

class Solution
{
public:
    int minSubArrayLen(int target, vector<int> &nums)
    {
        int size = nums.size();
        int slow = 0;  // 初始化慢指针
        int quick = 0; // 初始化快指针
        int sum = 0;   // 前缀和
        int returnlength = size + 1;

        for (; quick < size; quick++) 
        {
            sum = sum + nums[quick]; // 对前面的子数组进行求和
            if (sum >= target)       // 当前面的和小于目标值的时候,无法收缩,当和大于目标值的时候,才能收缩。
            {

                while ((sum - nums[slow]) >= target)//尝试缩小字数组区间
                {
                    sum = sum - nums[slow];
                    slow++;
                }

                returnlength = min(returnlength, quick - slow + 1);
            }
        }
        return returnlength == size + 1 ? 0 : returnlength;//如果所有的和都小于target,则返回0
    }
};

题13 盛最多的水

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

输入:[1,8,6,2,5,4,8,3,7]
输出:49 
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

示例 2:

输入:height = [1,1]
输出:1

 作题思路:

第一步:首先分析,最大的水的容量应该是Value =长*宽。那么长=(quick -slow)宽=min(height[quick],height[slow]),所以很明显,此题应该用双指针。通常双指针有两种用法。第一种是一个指向头,一个指向尾部,相反方向移动。第二种是两个都指向头,同方向移动。因此此题也有两种做法。

法一:

双指针,同方向移动。

从height[0]开始,遍历其后值和height[0]形成的大小,然后求最大值。

然后继续从height[1]开始,遍历其后值和height[0]形成的大小,然后求最大值。

缺点:

时间复杂度为N的平方。

法一代码案例:

class Solution
{
public:
    int maxArea(vector<int> &height)
    {
        int returnvalue = 0;//返回的最大值
        int slow = 0;//初始化慢指针
        int size = height.size();
        for (; slow < size - 1; slow++)//慢指针遍历
        {
            for (int quick = slow + 1; quick < size; quick++)//快指针遍历
            {
                int x = quick - slow;//获取长
                int y = min(height[quick], height[slow]);//获取宽
                returnvalue = max(returnvalue, x * y);//更新最大值
            }
        }

        return returnvalue;
    }
};

法二思路:

首先此题相当于找出任何两个y轴和x轴形成的长方形面积最大。那么双指针首先,就需要包含所有的可以作为长方形边界的范围。即

第一步:初始化慢指针slow指向头的位置,初始化快指针quick指向末尾的位置。

第二步:计算此时长方型的最大面积,那么此时长是x=quick -slow,y的值是min(height[quick], height[slow])。

第三步:移动指针,那么如何移动呢?假设,此时数组长度是5,height[quick]是6,height[slow]是1,首先如果移动较大的值,即我们放弃较大的值作为长方形的边界,

那么有以下三种情况:

1.如果height[quick-1]的值>=6,那么新的长方形,此时长是4,宽仍然是height[slow]的,此时

新的长方形最大面积是必然小于前一个值的。

2.如果height[slow]<height[quick-1]<6,那么新的长方形,此时长是4,宽仍然是height[slow]的,此时新的长方形最大面积是必然小于前一个值的。

3.如果height[quick-1]<height[slow],那么新的长方形,此时长是4,宽是height[quick-1],此时新的长方形最大面积是必然小于前一个值的。

那么此时我们就知道,当我们移动较大的边界值时候。其值永远都是更小的。

此时我们再分析一下移动较小的值。有以下几种情况。

1.如果height[slow+1]<=height[slow],则此时长从5变为4,则最大面积变小。

2.如果height[slow+1]>height[slow],则此时有可能新的长方形面积更大。

所以我们只能移动较小的那个边界值。

第四步:每次移动获取的值和最大值作比较,保留最大值。

第五步:当左边界和右边界重合时,说明所有可能比之前的长方形面积更大的都计算完了。

法二代码案例:

class Solution
{
public:
    int maxArea(vector<int> &height)
    {
        int returnvalue = 0;           // 返回的最大值
        int slow = 0;                  // 初始化慢指针指向头的位置
        int quick = height.size() - 1; // 初始化快指针指向末尾的位置

        while (slow < quick)
        {
            returnvalue = max(returnvalue, (quick - slow) * min(height[quick], height[slow]));

            if (height[quick] >= height[slow])
            {
                slow++;//如果右边界值大于左边界值,则移动左边界值
            }
            else
            {
                quick --;//如果右边界值小于左边界值,则移动右边界值
            }
        }

        return returnvalue;
    }
};

题14 三数之和

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

 思路:

首先对于数组的操作,能先排序就排序,能双指针就双指针。

此题也可以理解为:

遍历每一个值,然后从剩下的所有值中找两个其他的值,其三个的和等于0。

第一步:对数组排序,如果前三个最小的之和大于0,因为数组此时是递增的,那么后面不可能等于0,则返回。

假设此时数组长度是5。

第二步:固定第一个数字nums[0],此时我们的条件就变成了在剩下不包括nums[0]的数组中找到两个值,这两个值的和是-nums[0]。而此时是已经排序的数组。

第三步:让慢指针指向nums[1]的位置,快指针指向nums数组的尾部nums[4],然后判断nums[1]+nums[4] 和(0-nums[i])的大小。如果大于(0-nums[i]),则尾指针向左移动,如果小于则头指针向右移动。如果等于,则满足条件,此时如果没有重复值,则头指针向右移动并且尾指针向左移动。如果有重复值,则需要跳过。

想一想,如果此时满足条件的值是(-1,0,1),而nums[3]也等于-1,如果没跳过,则出现两个(-1,0,1),不满足条件。

第四步:然后遍历第二个元素,如果第二个等于第一个,则跳过,遍历下一个。然后重复第二步到第四步。

代码案例:

class Solution
{
public:
    vector<vector<int>> threeSum(vector<int> &nums)
    {
        vector<vector<int>> returnvector;
        if (nums.size() < 3)
        {
            return returnvector;
        }

        sort(nums.begin(), nums.end());

        if (nums[0] + nums[1] + nums[2] > 0)
        {
            return returnvector;
        }

        for (int i = 0; i < nums.size() - 2; i++)
        {
            if (i > 0 && nums[i] == nums[i - 1])
                continue;// 跳过重复的元素

            int slow = i + 1;//慢指针指向不要nums[i]的数组的头
            int quick = nums.size() - 1;慢指针指向不要nums[i]的数组的尾

            while (slow < quick)
            {
                int sum = nums[slow] + nums[quick] + nums[i];
                if (sum == 0)//当值相等的时候,则说明找到了
                {
                    returnvector.push_back({nums[i], nums[slow], nums[quick]});
                    while (slow < quick && nums[slow] == nums[slow + 1])
                        slow++; // 跳过重复的元素
                    while (slow < quick && nums[quick] == nums[quick - 1])
                        quick--; // 跳过重复的元素

                    slow++;
                    quick--;
                }
                else if (sum > 0)//当值大于0的时候,则说明我们我们需要移动数组尾端,让值变小一点
                {
                    quick--;
                }
                else if (sum < 0)//当值小于0的时候,则说明我们我们需要移动数组头端,让值变大一点
                {
                    slow++;
                }
            }
        }
        return returnvector;
    }
};

题15 最接近的三数之和

给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。

返回这三个数的和。

假定每组输入只存在恰好一个解。

示例 1:

输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

示例 2:

输入:nums = [0,0,0], target = 1
输出:0

 思路:

首先对于数组的操作,能先排序就排序,能双指针就双指针。

此题也可以理解为:

遍历每一个值,然后从剩下的所有值中找两个其他的值,其三个的和减去target的值的绝对值最小。

第一步:对数组进行排序,假如此时数组是nums=[-1,2,1,-4],排序后是[-4,-1,1,2]

第二步:因为要遍历所有值,所以第一次循环先挑选nums[0],然后,就变成了在[-1,1,2]中,选择任意两个值,判断三个的和减去target的值的绝对值最小。

第三步:慢指针指向-1,快指针指向2,此时判断nums[0]+nums[slow]+nums[quick] -target的值。

1.如果A[0]+A[slow]+A[quick] -target =0,则直接返回sum = target。

2.如果A[0]+A[slow]+A[quick] -target >0, 尾指针得向左移动 ,如果前三个和大于taraget,则说明要找到下一个更小的。这样可能更靠近target。此时尾指针向左移动,此时需要计算temp - target的绝对值和上一个绝对值的大小,如果当前三个数和的绝对值小于之前的绝对值,则更新sum。

3.如果前三个和小于taraget,则说明要找到更大的。这样可能更靠近target。此时头指针向右移动,此时需要计算temp - target的绝对值和上一个绝对值的大小,如果当前三个数和的绝对值小于之前的绝对值,则更新sum。

此时我们在第一次循环中就找到了以第一个元素为首的与target距离最近的三个数的和。

第二次循环继续重复第二步和第三步,这样就找出了第二个数组为首的三个数,与target距离最近的。依次遍历就找到了所有的子集中与与target距离最近的。

 代码案例:

class Solution
{
public:
    int threeSumClosest(vector<int> &nums, int target)
    {
        int sum = 0;
        int closevalue = INT32_MAX;//初始化为做大值,因为后面要取min

        sort(nums.begin(), nums.end()); //排序

        for (int first = 0; first < nums.size() - 2; first++)
        {
            int slow = first + 1;
            int quick = nums.size() - 1;

            while (slow < quick)
            {
                int temp = nums[first] + nums[slow] + nums[quick];//计算前三个的和
                if (temp - target == 0)//如果等于taraget,则直接返回
                {
                    return temp;
                }
                else if (temp - target > 0) //如果前三个和大于taraget,则说明要找到下一个更小的。这样可能更靠近target。此时尾指针向左移动,
                //此时需要计算temp - target的绝对值和上一个绝对值的大小,如果当前三个数和的绝对值小于之前的绝对值,则更新sum
                {

                    if (abs(temp - target) < closevalue)
                    {
                        closevalue = min(abs(temp - target), closevalue);
                        sum = temp;
                    }
                    quick--;
                }
                else if (temp - target < 0)
                {
                    if (abs(temp - target) < closevalue)//如果前三个和小于taraget,则说明要找到更大的。这样可能更靠近target。此时头指针向右移动,
                //此时需要计算temp - target的绝对值和上一个绝对值的大小,如果当前三个数和的绝对值小于之前的绝对值,则更新sum
                    {
                        closevalue = min(abs(temp - target), closevalue);
                        sum = temp;
                    }
                    slow++;
                }
            }
        }

        return sum;
    }
};

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

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

相关文章

齐普夫定律在循环神经网络中的语言模型的应用

目录 齐普夫定律解释公式解释图与公式的关系代码与图的分析结论 使用对数表达方式的原因1. 线性化非线性关系2. 方便数据可视化和分析3. 降低数值范围4. 方便参数估计公式详细解释结论 来自&#xff1a;https://zh-v2.d2l.ai/chapter_recurrent-neural-networks/language-model…

企业网站安装OV SSL证书的必要性

一、什么是OV SSL证书 SSL OV证书&#xff0c;即组织验证型SSL证书&#xff0c;它要求证书颁发机构对申请证书的组织进行身份验证&#xff0c;确认组织的真实性后&#xff0c;才会发放证书。这种验证方式提高了安全性&#xff0c;因为它确保了证书背后的实体是真实存在的组织&…

SpringBoot实现图片文件上传和回显的两种方式

目录 一 功能需求 二 上传本地 2.1 实现文件上传的controller层 2.2 图片访问资源映射 二 上传OSS 一 功能需求 实现图片的上传和回显功能其实在业务中是非常常见的,比如需要上传头像,或者交易平台需要上传物品的图片等等,都需要上传和回显,所以我接下来给大家介绍两种…

VsCode中C文件调用其他C文件函数失败

之前一直使用CodeBlocks&#xff0c;最近使用vscode多&#xff0c;感觉它比较方便&#xff0c;但在调用其他C文件的时候发现报错以下内容基于单C文件运行成功&#xff0c;否则请移步 博文&#xff1a;VSCode上搭建C/C开发环境 报错信息 没有使用CodeRunner插件&#xff0c;弹…

ubuntu第三方库离线安装包(.deb离线安装方法;apt离线安装;离线安装deb)(docker离线安装、安装docker安装)

文章目录 方法1&#xff1a;Ubuntu Packages 网站下载离线包&#xff08;失败了&#xff0c;找不到包的可下载源&#xff0c;有的包有&#xff0c;有的包没有&#xff0c;不知道怎么回事&#xff09;操作步骤1. 在有网络的环境中&#xff0c;打开浏览器并访问 Ubuntu Packages …

读取CSV文件生成RDD去掉标题行

文章目录 1. 创建CSV文件2. 上传CSV文件3. 读取CSV文件生成RDD4. 去掉标题行生成新RDD5. 查看新生成的RDD 1. 创建CSV文件 执行命令&#xff1a;vim scores.csv 在WPS里查看CSV文件 2. 上传CSV文件 执行命令&#xff1a;hdfs dfs -put scores.csv /park 3. 读取CSV文件生…

Content type ‘application/x-www-form-urlencoded;charset=UTF-8‘ not supported

Content type application/x-www-form-urlencoded;charsetUTF-8 not supported 问题背景新增页面代码改造 问题背景 这里有一个需求&#xff0c;前端页面需要往后端传参&#xff0c;参数包括主表数据字段以及子表数据字段&#xff0c;由于主表与子表为一对多关系&#xff0c;在…

计算机毕业设计Python+Django农产品推荐系统 农产品爬虫 农产品商城 农产品大数据 农产品数据分析可视化 PySpark Hadoop Hive

课题研究的意义&#xff0c;国内外研究现状、水平和发展趋势 研究意义21世纪是一个信息爆炸的时代&#xff0c;人们在日常生活中可接触到的信息量非常之巨大。推荐系统逐步发展&#xff0c;其中又以个性化推荐系统最为瞩目。个性化推荐系统的核心在于个性化推荐算法&#xff0c…

【python】 pandas.DataFrame.to_json 函数

【python】 pandas.DataFrame.to_json 函数 写在最前面一、什么是 JSON&#xff1f;【性能对比】python读取json和直接从orcle数据库读&#xff0c;哪个更快&#xff1f;性能对比适用场景综合考虑 二、to_json 函数概述参数详解1. path_or_buf2. orient4. double_precision5. f…

SaaS产品运营 | 千万不能踏入的PLG模式的六大误区

随着科技的迅速发展和市场竞争的日益激烈&#xff0c;越来越多的公司开始尝试采用PLG&#xff08;Product Led Growth&#xff0c;即产品驱动增长&#xff09;模式来推动其业务的发展。然而&#xff0c;尽管PLG模式在促进增长方面具有显著优势&#xff0c;但在实践中也容易出现…

python学习 -You-Get视频下载使用案例

You-Get 是一个命令行程序&#xff0c;提供便利的方式来下载网络上的媒体信息。 You-Get 是一个用于从网页下载媒体内容&#xff08;如视频、音频、图片&#xff09;的Python库。它支持多种网站&#xff0c;能够捕获并下载这些网站中直接或间接提供的媒体资源。You-Get 的设计…

BarTender软件下载附加详细安装教程

BarTender是美国海鸥科技推出的一款优秀的条码打印软件&#xff0c;应用于 WINDOWS95 、 98 、 NT 、 XP 、 2000 、 2003 和 3.1 版本&#xff0c; 产品支持广泛的条形码码制和条形码打印机&#xff0c; 不但支持条形码打印机而且支持激光打印机&#xff0c;还为世界知名品牌条…

比特币对接文档

比特币对接 地址分类 p2sk()p2skh(主网地址是以"1"开头,例如:16dN3XhaTejyZFy4hWompK2x8de2T46wA8; 测试网是以"m"或"n"开头, 例如:mvZjn2485hwxjVPJoLAZVyJKUDn8aGpBy5)p2sh (主网地址是以"3"开头,例如:33ZzFZZJcvtnLBWRdne6F9SpD9…

数据结构笔记1-19(补充之前没有提及的细节)

目录 算法的五大特征 时间复杂度 next数组 nextval数组 树结点的计算 满二叉树和完全二叉树 线索二叉树 树的存储结构 森林、树之间的转换 哈夫曼树的构造 这几个红框&#xff0c;因为之前在别的视频有学过了&#xff0c;故不再看了。如果到时候还有什么需要查缺补…

[项目推荐]EmoLLM-心理健康大模型

EmoLLM 是一系列能够支持理解用户-支持用户-帮助用户心理健康辅导链路的开源心理健康大模型&#xff0c;由LLM指令微调而来。它旨在全面理解和促进个体、群体乃至整个社会的心理健康状态。 项目介绍 GitHub&#xff1a;https://github.com/SmartFlowAI/EmoLLM 【EmoLLM项目提供…

如何基于Excel文件图形化从零建表并导入数据(以MySQL和SQLynx为例)

目录 1. 准备Excel数据 2. 导入Excel数据 a. 登录SQLynx b. 导入Excel文件 3. 验证数据 4. 使用和管理表 5. 总结 在实际的业务过程中&#xff0c;我们经常会有很多数据存储在Excel中&#xff0c;但在Excel中的数据分析不如使用SQL和数据库方便&#xff0c;数据量大些的…

VS修改项目名称

本文以Visual Studio2015为例 1.VS体系是由一个个单独项目组成一个解决方案&#xff0c;如果要修改解决方案名称直接右击——重命名。 修改解决方案下的项目名称&#xff1a;选中项目名称——右击——重命名 同时修改项目所在路径下的同名文件夹名称和里面的项目名称.vcxproj、…

【仿真建模-anylogic】EventRate原理解析

Author&#xff1a;赵志乾 Date&#xff1a;2024-06-13 Declaration&#xff1a;All Right Reserved&#xff01;&#xff01;&#xff01; 1. 类图 2. 原理解析 EventOriginator是Anylogic中各类事件的父类&#xff0c;对外暴露的接口主要有: 函数功能boolean isActive()判定…

人类如何挣脱被人工智能替代的命运?

人工智能技术的迭代升级&#xff0c;使得“换脸”“拟声”成为可能&#xff0c;我如何证明不是“我”&#xff1f;面对人工智能超高的生产效率&#xff0c;我如何与人工智能“抢工作”&#xff1f;在人工智能时代&#xff0c;如何回应这类疑问&#xff1f;挣脱被替代的命运&…

Windows 11 24H2版首发体验!附详细更新升级安装教程

Windows 11 24H2 版首发体验&#xff01;这是微软2024年的大版本更新&#xff0c;新增超多新功能&#xff0c;以下会给你细细道来。这个版本目前小编亲测&#xff0c;使用非常流畅&#xff0c;没有什么明显问题。系统是已经集成了VB6/VC2005/VC2008/VC2010/VC2012/VC2013/VC201…