算法是如何一步一步优化的?

这篇具有很好参考价值的文章主要介绍了算法是如何一步一步优化的?。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

英雄算法联盟 - 七月集训 已经开始 6 天,八月算法集训 将于 08月01日 正式开始,目前已经提前开始报名,报名方式参见(八月算法集训报名),想要参加的同学,建议提早报名,因为对于算法零基础的同学,会有一些提前的准备工作,比如需要 1 - 5 天的时间完成预训练 和 九日集训 提前养成刷题的习惯,再参加算法集训会更加有成效。

零、题目描述

视频版本👉🏻英雄哪里出来 抖音。

给定一个长度为 n 的整数数组,数组下标从 0 开始。请返回上升四元组的数目,如果四元组满足如下条件:
1) 0 <= i < j < k < l < n
2) nums[i] < nums[k] < nums[j] < nums[l]
则这个四元组是上升的

一、 O ( n 4 ) O(n^4) O(n4) 理解错题意版本

  既然是四元组,当然要定义四个变量啦。ijkl分别代表四个递增的下标,定义四元组数目 ans,初始化为 0
  枚举 i0n-1
  枚举 ji+1n-1
  枚举 kj+1n-1
  枚举 lk+1n-1
  如果 a[i] < a[j],并且 a[j] < a[k],并且 a[k] < a[l],那么就是一个满足条件的四元组,结果的值加一。最后返回 ans,就是我们要求的解啦。提交,错辣!

long long countQuadruplets(int* a, int n){
    int i, j, k, l;
    long long ans = 0;
    for(i = 0; i < n; ++i) {
        for(j = i + 1; j < n; ++j) {
            for(k = j + 1; k < n; ++k) {
                for(l = k + 1; l < n; ++l) {
                    if(a[i] < a[j] 
                    && a[j] < a[k] 
                    && a[k] < a[l]) ++ans;
                }
            }
        }
    }
    return ans;
}

二、 O ( n 4 ) O(n^4) O(n4) 超时版本

  哦哦哦哦哦!jk的位置反了,这个题也太 baby 啦!(明明是自己没有认真审题啊),修改后运行,没什么问题,提交!

long long countQuadruplets(int* a, int n){
    int i, j, k, l;
    long long ans = 0;
    for(i = 0; i < n; ++i) {
        for(j = i + 1; j < n; ++j) {
            for(k = j + 1; k < n; ++k) {
                for(l = k + 1; l < n; ++l) {
                    if(a[i] < a[k] 
                    && a[k] < a[j] 
                    && a[j] < a[l]) ++ans;
                }
            }
        }
    }
    return ans;
}

  超时啦!嘶……

三、 O ( n 4 ) O(n^4) O(n4) 简单优化后又错辣

  哦哦哦哦哦!
  a[i]a[k]完全不需要放到这个循环。提出来,如果 a[i]大于等于 a[k],直接跳过,去掉这个判断。
  a[k]a[j]也不需要放到这个循环。提出来,如果 a[k]大于等于 a[j]直接跳过,去掉这个判断。

long long countQuadruplets(int* a, int n){
    int i, j, k, l;
    long long ans = 0;
    for(i = 0; i < n; ++i) {
        for(j = i + 1; j < n; ++j) {
            for(k = j + 1; k < n; ++k) {
                if(a[i] >= a[k]) continue;
                if(a[k] >= a[j]) conitnue;
                for(l = k + 1; l < n; ++l) {
                    if(a[j] < a[l]) ++ans;
                }
            }
        }
    }
    return ans;
}

提交!编译错误?!

四、 O ( n 4 ) O(n^4) O(n4) 简单优化超时

  哦哦哦哦哦!

long long countQuadruplets(int* a, int n){
    int i, j, k, l;
    long long ans = 0;
    for(i = 0; i < n; ++i) {
        for(j = i + 1; j < n; ++j) {
            for(k = j + 1; k < n; ++k) {
                if(a[i] >= a[k]) continue;
                if(a[k] >= a[j]) continue;
                for(l = k + 1; l < n; ++l) {
                    if(a[j] < a[l]) ++ans;
                }
            }
        }
    }
    return ans;
}

continue 拼错啦!恶业~改一下没问题,提交!又超时啦!

五、 O ( n 3 ) O(n^3) O(n3) 超时

  啊爱爱爱爱啊!四个 for 循环, O ( n 4 ) O(n^4) O(n4) 的时间复杂度,算算了,换成 O ( n 3 ) O (n^3) O(n3) 的算法好了,枚举中间两个数,第一个数下标 j1n-1;第二个数下标 kj+1n-1,如果 a[k]大于等于 a[j],则必然不满足条件的四元组,直接跳过。
  否则定义一个less变量,记录 0j-1的数中小于 a[k]的数的个数;再定义一个bigger变量,记录 k+1n-1的数中大于 a[j]的数的个数。
  然后利用乘法原理 less * bigger累加到 ans上,就把所有满足条件的四元组都统计出来啦!运行,没什么问题。

long long countQuadruplets(int* a, int n){
    int i, j, k, l;
    long long ans = 0;

    for(j = 1; j < n; ++j) {
        for(k = j + 1; k < n; ++k) {
            if(a[k] >= a[j]) {
                continue;
            }
            int less = 0;
            for(i = 0; i < j; ++i) {
                if(a[i] < a[k]) ++less;
            }
            int bigger = 0;
            for(l = k + 1; l < n; ++l) {
                if(a[l] > a[j]) ++bigger;
            }
            ans += less * bigger;
        }
    }
    return ans;
}

  提交!又又超时啦!
  这数据什么情况,哇靠!n最大是 4000,那 O ( n 3 ) O(n^3) O(n3) 肯定就超时啦!起码得想个 O ( n 2 ) O(n^2) O(n2) 的算法。

六、 O ( n 2 ) O(n^2) O(n2)

  哦哦哦哦哦!
  只要把求 lessbigger
的 for 循环变成 O(1)不就好了!
  1)定义一个宏maxn4001,定义一个less矩阵和bigger矩阵,其中 less[i][j]代表 0i-1的数中小于 j的个数;其中 bigger[i][j]代表 i+1n-1的数中大于 j的个数;
  2)对于任意的 j < ka[k] < a[j],将 less[j][a[k]]bigger[k][a[j]]相乘,累加就是答案了。
  3)然后就是求 less矩阵 和 bigger矩阵的过程啦。封装成两个函数,先求 calcLessless[0][i]代表第 0个数前面的数中,小于 i的数的个数,自然是 0,然后枚举 1n-1a[i-1]缓存到 x上,枚举 j1n,如果 x < j,就代表 less[i][j]就是 less[i-1][j],加上一个数,也就是 x这个数,否则 less[i][j]的值,就是 less[i-1][j]的值。
  4)用同样的方法计算 calcBiggerbigger[n-1][i]代表 n-1后面的数中,大于i的数的个数,显然是 0,然后逆序枚举 n-20,将 a[i+1]缓存到 x上,枚举 j1n,如果 x > j,就代表 bigger[i][j]就是bigger[i+1][j]加上一个数,也就是 x这个数,否则 bigger[i][j]的值 就是 bigger[i+1][j]的值。
  5)最后把 less [j][ a[k] ]bigger[k][ a[j] ]累乘以后累加到 ans上。提交!

#define maxn 4001
int less[maxn][maxn], bigger[maxn][maxn];
// less[i][j] 代表 0 到 i-1 的数中,小于 j 的个数
// bigger[i][j] 代表 i+1 到 n-1 的数中,大于 j 的个数
// 对于任意 j < k, 且 a[k] < a[j]
// 累加 less[j][ a[k] ] * bigger[k][ a[j] ]

void calcLess(int *a, int n) {
    for(int i = 1; i <= n; ++i) {
        less[0][i] = 0;
    }
    for(int i = 1; i < n; ++i) {
        int x = a[i-1];
        for(int j = 1; j <= n; ++j) {
            if(x < j) {
                less[i][j] = less[i-1][j] + 1;
            }else {
                less[i][j] = less[i-1][j];
            }
        }
    }
}

void calcBigger(int *a, int n) {
    for(int i = 1; i <= n; ++i) {
        bigger[n-1][i] = 0;
    }
    for(int i = n-2; i >= 0; --i) {
        int x = a[i+1];
        for(int j = 1; j <= n; ++j) {
            if(x > j) {
                bigger[i][j] = bigger[i+1][j] + 1;
            }else {
                bigger[i][j] = bigger[i+1][j];
            }
        }
    }
}

long long countQuadruplets(int* a, int n){
    calcLess(a, n);
    calcBigger(a, n);
    long long ans = 0;
    for(int j = 0; j < n; ++j) {
        for(int k = j + 1; k < n; ++k) {
            if(a[k] < a[j]) {
                ans += less[j][ a[k] ] * bigger[k][ a[j] ];
            }
        }
    }
    return ans;
}

过啦!!!打败了100%的人!文章来源地址https://www.toymoban.com/news/detail-525118.html

到了这里,关于算法是如何一步一步优化的?的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构的魔法:高级算法优化实战

    🎉欢迎来到数据结构学习专栏~数据结构的魔法:高级算法优化实战 ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹 ✨博客主页:IT·陈寒的博客 🎈该系列文章专栏:数据结构学习 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习 🍹文章作者技术和水平有

    2024年02月06日
    浏览(44)
  • 【数据结构与算法】排序算法:冒泡排序,冒泡排序优化,选择排序、选择排序优化

    目录 一、冒泡排序 1、冒泡排序思想 2、冒泡排序算法的性能分析 代码实现: 二、选择排序 1、选择排序思想 2、选择排序算法的性能分析  代码实现: 1、冒泡排序思想 冒泡排序的基本思想是通过相邻元素之间的比较和交换来逐步将最大(或最小)的元素移到右边(或左边

    2024年01月19日
    浏览(50)
  • C++中的算法与数据结构优化技巧

    在C++编程中,算法和数据结构的优化是提高程序性能和效率的关键因素之一。下面是一些常见的算法和数据结构优化技巧,希望对您有帮助: 选择合适的数据结构:数据结构的选择对算法效率有重要影响。根据具体问题的需求,选择合适的数据结构,如数组、链表、树、散列

    2024年01月17日
    浏览(43)
  • 如何一步一步构建网站ChatGPT插件

    在本文中,我们将一步一步地探索并构建一个名为\\\"AI Prompt Testing\\\"的项目。该项目是一个网站插件,旨在帮助网站生成一个ChatGPT提示测试题,以巩固当前网页的内容。 这个网站ChatGPT插件大概的效果,类比的实现有哪些? addtoany, google analytics addtoany的配置是这样子 google anal

    2024年02月04日
    浏览(65)
  • 【数据结构 | 入门】线性表与链表 (问题引入&实现&算法优化)

    🤵‍♂️ 个人主页: @计算机魔术师 👨‍💻 作者简介:CSDN内容合伙人,全栈领域优质创作者。 本文是浙大数据结构学习笔记专栏 这里我们引入一个问题,最常见的多项式,我们如何使用编程将多项式表示出来呢? 我们可以使用数组来表示,但是会随着一个问题,如下图底

    2024年01月21日
    浏览(71)
  • 【数据结构】字符串匹配|BF算法|KMP算法|next数组的优化

    字符串匹配算法是在实际工程中经常遇到的问题,也是各大公司笔试面试的常考题目,本文主要介绍BF算法(最好想到的算法,也最好实现)和KMP算法(最经典的) BF算法,即暴力(Brute Force)算法,是普通的模式匹配算法,BF算法的思想就是将目标S的第一个字符与模式串T的第一

    2024年02月04日
    浏览(56)
  • 算法 数据结构 递归插入排序 java插入排序 递归求解插入排序算法 如何用递归写插入排序 插入排序动图 插入排序优化 数据结构(十)

    1. 插入排序(insertion-sort):                                           是一种简单直观的排序算法。它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入     算法稳定性:                  

    2024年02月09日
    浏览(56)
  • 优化后端系统的计算和存储效率 - 高效算法与数据结构

    在构建后端系统时,高效的算法与数据结构是至关重要的。它们可以显著提升计算和存储效率,从而使系统更稳定、快速且可扩展。本文将介绍一些常见的高效算法和数据结构,以及它们在优化后端系统中的应用。 哈希表是一种常用的数据结构,它通过将键映射到一个固定大

    2024年02月11日
    浏览(49)
  • 【算法与数据结构】2 梅开二度,线性查找的究极优化

    欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享,与更多的人进行学习交流 本文收录于算法与数据结构体系专栏, 本专栏 对于0基础者极为友好,欢迎与我一起完成算法与数据结构的从0到1的跨越 在上篇文章中,详细讲述了线性查找法并且对其进行了 初步的优化 :

    2024年02月02日
    浏览(35)
  • 【算法与数据结构】深入二叉树实现超详解(全源码优化)

    上节我们学习了二叉树(前中后)序遍历 这节将实现二叉树。 让我们复习一下二叉树,接着就是二叉树的实现了😊,学习起来吧! 满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总

    2024年04月11日
    浏览(76)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包