双指针(5)_单调性_有效三角形的个数

news2024/9/20 15:02:28

个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创

双指针(5)_单调性_有效三角形的个数

收录于专栏【经典算法练习
本专栏旨在分享学习C++的一点学习笔记,欢迎大家在评论区交流讨论💌

目录

1. 题目链接:

2.题目描述 :

3.解法 :

    解法一(暴力枚举) :

    算法思路 :

    代码展示 :

暴力枚举优化:

    结果分析 :

    解法二(排序 + 双指针) :

    算法思路 :

    代码展示 :

    结果分析 :

    4.总结 :


1. 题目链接:

--------有效三角形的个数

2.题目描述 :

给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。

示例 1:

输入: nums = [2,2,3,4]
输出: 3
解释:有效的组合是: 
2,3,4 (使用第一个 2)
2,3,4 (使用第二个 2)
2,2,3

示例 2:

输入: nums = [4,2,3,4]
输出: 4

提示:

  • 1 <= nums.length <= 1000
  • 0 <= nums[i] <= 1000

3.解法 :

    解法一(暴力枚举) :

    算法思路 :

利用三层for循环遍历整个数组

注意:

1. 这道题不需要去重处理,比如示例一中的2,3,4出现了两次,但其中的2分别是第一个和第二个.

2. 这道题的数据范围:nums.lengh <= 1000,我们三层for循环时间复杂度就为O(n^3),我们还需要进行判断,整体下来还是O(N^3),数据量超过10^9,可能会超时!!!

伪代码展示:

for (int i = 0; i < n; i++)
{
	for (int j = i + 1; j < n; j++)
	{
		for (int k = j + 1; k < n; k++)
		{
			check(i, j, k);
		}
	}
}

    代码展示 :

class Solution {
public:
    bool check(int a, int b, int c)
    {
        if((a + c > b) && (a + b > c) && (b + c > a)) return true;
        else return false;
    }
    int triangleNumber(vector<int>& nums) {
        int sum = 0, n = nums.size();
        for(int i = 0; i < n; i++)
            for(int j = i + 1; j < n; j++)
                for(int k = j + 1; k < n; k++)
                    if(check(nums[i], nums[j], nums[k])) sum++;
        return sum;
    }
};

 

很显然,在算法题中想要用暴力做出来是基本不可能的,更何况这道题还是中等的难度,通过率仅仅50%,这里我使用暴力只通过了231个例子,这里说一下暴力算法主要是为了蓝桥杯(暴力杯),当我们没有思路时,可以选择暴力方法通过一部分例子,也可以帮助我们分析题目.

优化暴力算法: 

我们可以发现,我们使用三层循环时间复杂度为O(N^3),数据量为10^9,按道理应该勉强能过,但实际上,我们三层循环里还要进行一次判断,所以时间复杂度可以细化为O(3N^3),那我们能不能把判断这个环节进行优化呢?答案是可以的!

优化判断函数check:

假设我们的数组是有序的,拿我们判断三个有序的数是否能构成三角形是不是只需要判断a + b > c就可以了,因为a <= b, b <= c,那我们的a + c一定是大于b,同理b + c 也一定大于a.

在这个思路上,我们就可以首先对数组进行排序,排序的时间为O(Nlog(N))(sort底层用的是快排),这样三层循环内的判断只需要进行一次,总体时间复杂度为O(N^3 + Nlog(N)) 是远小于 O(3N^3)的,我们看一下优化后的暴力算法能不能蒙混过关!

暴力枚举优化:

class Solution {
public:
    bool check(int a, int b, int c)
    {
        if(a + b > c) return true;
        else return false;
    }
    int triangleNumber(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        int sum = 0, n = nums.size();
        for(int i = 0; i < n; i++)
            for(int j = i + 1; j < n; j++)
                for(int k = j + 1; k < n; k++)
                    if(check(nums[i], nums[j], nums[k])) sum++;
        return sum;
    }
};

 

???????????????????????????????????????????????????????????????

不是,我就试一试,你就让我过了?

这道题真是中等难度吗?

说实话,我一开始只是认为会多通过几个例子,没想到它直接通过了!!!

那现在看来暴力算法还是可以作为先锋的,万一过了呢?

    结果分析 :

因为这道题数据给的比较低,数组中的数小于1000,这就给了暴力算法窜了空子,稍微优化一下,我们的暴力算法就可以通过.

但是,假如这道题数组中的数小于10000时,暴力算法无论怎么优化都不行,因为它的时间复杂度本质就是O(N^3),当数据量为10000时,我们就得考虑时间复杂度为O(N^2)或者O(Nlog(N))的算法了

    解法二(排序 + 双指针) :

    算法思路 :

先将数组排序.

根据[解法一]中的优化思想,我们可以固定一个[最长边],然后在比这条小的有序数组中找出一个二元组,使这个二元组之和大于这个最长边.由于数组是有序的,我们可以利用[对撞指针]来优化.

设最长枚举i位置,区间[left, right]是i位置的左边的区间(也就是比它小的区间):

        如果nums[left] + nums[right] > nums[i]:

                说明[left, right-1] 区间上的所有元素均可以与nums[right]构成比nums[i]大的二元组

                满足条件的有right - left

                此时right位置的元素的所有情况相当于全部考虑完毕,right--,进入下一轮判断

        如果nums[left] + nums[right] <= nums[i]:

                说明left位置的元素是不可能与[left + 1, right]位置上的元素构成满足条件的二元组

                left位置的元素可以舍去,left++进入下轮循环

思路图解:

 

    代码展示 :

class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        int sum = 0, n = nums.size() - 1;
        while(n >= 2)
        {
            int left = 0, right = n - 1;
            while(left < right)
            {
                if(nums[left] + nums[right] > nums[n]) sum += right - left, right--;
                else left++;
            }
            n--;
        }
        return sum;
    }
};

 

    结果分析 :

顺利通过!!!

时间复杂度分析:

外层n进行了一层循环,内层left和right共同完成了对数组的遍历

整体的时间复杂度为O(N^2),比前面的暴力算法还是快了不少!!!

    4.总结 :

大家做算题题时,一定要优先查看题目的数据范围,这样能提前Pass掉一些时间复杂度过高的方法,为大家节约时间,当然如果你实在没招,暴力枚举你可以尝试一下,特别是在蓝桥杯中!!!

最后我每天都会更新一道经典算法题(正常情况下),感兴趣的宝子们可以关注我!!!

欢迎 点赞👍 收藏✨ 留言✉ 加关注💓

所有算法题我都会放在我的专栏[经典算法练习],大家也可以关注下,我们明天见!!!

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

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

相关文章

c++stack和list 介绍

stack介绍 堆栈是一种容器适配器&#xff0c;专门设计用于在 LIFO 上下文&#xff08;后进先出&#xff09;中运行&#xff0c;其中元素仅从容器的一端插入和提取。 堆栈作为容器适配器实现&#xff0c;容器适配器是使用特定容器类的封装对象作为其基础容器 的类&#xff0c;提…

mysql可重复读不能解决幻读吗?

1、可重复读和幻读的概念 1.1、可重复读 可重复读是数据库的四个隔离级别之一,可重复读可以保证在一个事物之内读取到的数据永远是相同的(通过mvcc表快照实现的),哪怕这期间有其它事务对数据做了修改,也不会影响当前事务的查询。 1.2、幻读 网上有不少博客说:幻读是一个事物内…

正规表达式例题

解析&#xff1a;从题意可知&#xff0c;a可以有零个或多个&#xff0c;b有1个或多个 选项A&#xff1a;这里a至少有1个&#xff0c;不符合题意 选项B&#xff1a;a^*bb^*&#xff0c;a是0个或多个&#xff0c;b可以是1个或多个&#xff0c;符合题意 选项C和选项D&#xff0…

Jenkins 通过 Version Number Plugin 自动生成和管理构建的版本号

步骤 1&#xff1a;安装 Version Number Plugin 登录 Jenkins 的管理界面。进入 “Manage Jenkins” -> “Manage Plugins”。在 “Available” 选项卡中搜索 “Version Number Plugin”。选中并安装插件&#xff0c;完成后可能需要重启 Jenkins。 步骤 2&#xff1a;配置…

尚品汇-支付宝下单接口显示二维码实现(四十六)

目录&#xff1a; &#xff08;1&#xff09;支付功能实现 &#xff08;2&#xff09;保存支付信息 &#xff08;3&#xff09;编写支付宝支付接口 &#xff08;1&#xff09;支付功能实现 支付宝有了同步通知为什么还需要异步通知&#xff1f; 同步回调两个作用 第一是从支付…

密保管家-随机密码本地生成

下载 简介 安全无忧:采用先进的加密算法,确保您的密码安全不外泄。 随机性强:每次生成的密码都是完全随机的,避免模式化,增加破解难度。 易于管理:简洁的界面设计让您轻松管理所有账号的密码。 独立运行:无需网络连接,所有数据本地存储,保护隐私的同时提供便捷的密…

【MATLAB】模拟退火算法

模拟退火算法的MATLAB实现 模拟退火算法简介模拟退火算法应用实例关于计算结果 模拟退火算法简介 1982年&#xff0c;Kirkpatrick 将退火思想引入组合优化领域&#xff0c;提出了一种能够有效解决大规模组合优化问题的算法&#xff0c;尤其对 NP 完全问题表现出显著优势。模拟…

FreeRTOS 优先级翻转以及互斥信号量

优先级翻转&#xff1a; 高优先级的任务反而慢执行&#xff0c;低优先级的任务反而优先执行 优先级翻转在抢占式内核中是非常常见的&#xff0c;但是在实时操作系统中是不允许出现优先级翻转的&#xff0c;因为优先级翻转会破坏任务的预期顺序&#xff0c;可能会导致未知的严重…

react | 自学笔记 | 持续更新

React自学速学笔记 数据单向流动事件为什么上述例子&#xff0c;是onClick{()>shoot("goal!")}而不是onClick{shoot("goal")}?event对象 条件渲染if方法&&?: 三元表达式 纯小白自学笔记&#xff0c;有不对的欢迎指正。 数据单向流动 单向流动…

如何确保光伏电站EPC施工的质量

说到保证EPC施工的质量&#xff0c;我们得先了解什么是EPC施工&#xff0c;是指&#xff1a;指总承包商按照合同约定&#xff0c;承担工程项目的设计、采购、施工等工作&#xff0c;并对工程的质量、安全、工期和造价全面负责。 EPC施工还有几个特点&#xff1a; 一体化服务&…

单片机毕业设计基于stm32的蔬菜大棚智能监控系统设计

文章目录 前言资料获取设计介绍功能介绍程序代码部分参考 设计清单具体实现截图参考文献设计获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师&#xff0c;一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP…

2.2.3 UDP的可靠传输协议QUIC 2

udp可靠传输 kcp协议 网络通畅下&#xff0c;kcp比tcp慢 这里直接看课件图片&#xff0c; 延迟ack比非延迟减少应答包数量&#xff0c;但是慢 kcp 讲解 kan代码ikcp.c 按照readme指南编译一下&#xff01;&#xff01; mkdir build cd build cmake .. make第一遍报错&#xf…

ant-design-vue中实现a-tree树形控件父子关联选中过滤的算法

在使用ant-design-vue的框架时&#xff0c;a-tree是比较常用的组件&#xff0c;比较适合处理树形结构的数据。 但是在与后台数据进行授权交互时&#xff0c;就不友好了。 在原生官方文档的例子中&#xff0c;若子项被勾选&#xff0c;则父级节点会被关联勾选&#xff0c;但这勾…

【堆的应用--C语言版】

前面一节我们都已将堆的结构&#xff08;顺序存储&#xff09;已经实现&#xff0c;对树的相关概念以及知识做了一定的了解。其中我们在实现删除操作和插入操作的时候&#xff0c;我们还同时实现了建大堆&#xff08;小堆&#xff09;的向上&#xff08;下&#xff09;调整算法…

【CSS in Depth 2 精译_024】4.2 弹性子元素的大小

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第一章 层叠、优先级与继承&#xff08;已完结&#xff09; 1.1 层叠1.2 继承1.3 特殊值1.4 简写属性1.5 CSS 渐进式增强技术1.6 本章小结 第二章 相对单位&#xff08;已完结&#xff09; 2.1 相对…

PyInstaller问题解决 onnxruntime-gpu 使用GPU和CUDA加速模型推理

前言 在模型推理时&#xff0c;需要使用GPU加速&#xff0c;相关的CUDA和CUDNN安装好后&#xff0c;通过onnxruntime-gpu实现。 直接运行python程序是正常使用GPU的&#xff0c;如果使用PyInstaller将.py文件打包为.exe&#xff0c;发现只能使用CPU推理了。 本文分析这个问题…

TL-Tomcat中长连接的底层源码原理实现

长连接&#xff1a;浏览器告诉tomcat不要将请求关掉。 如果不是长连接&#xff0c;tomcat响应后会告诉浏览器把这个连接关掉。 tomcat中有一个缓冲区 如果发送大批量数据后 又不处理 那么会堆积缓冲区 后面的请求会越来越慢。

Java架构师未来篇大模型

目录 1. 大模型的定义2 大模型相关概念区分3 大模型的发展历程4. 大模型的特点5 大模型的分类6 大模型的泛化与微调7 大模型岗位需求8 理解大模型8.1 生活中的比喻8.2 大模型的定义9 大模型工作9.1 数据的积累9.2 模型的训练9.3 预测和应用10 大模型的实际应用10.1 语言处理10.…

240907-Gradio插入Mermaid流程图并自适应浏览器高度

A. 最终效果 B. 示例代码 import gradio as grmermaid_code """ <iframe srcdoc <!DOCTYPE html> <html><head><meta charset"utf-8" /><meta name"viewport" content"widthdevice-width" />…

C++初阶:STL详解(一)——string类

✨✨小新课堂开课了&#xff0c;欢迎欢迎~✨✨ &#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;C&#xff1a;由浅入深篇 小新的主页&#xff1a;编程版小新-CSDN博客 1.为什么会有string类 C 语言中&#xff0c…