热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

P1923:深入解析与优化策略

在探讨P1923问题时,我们发现手写的快速排序在最后两个测试用例中出现了超时现象,这在意料之中,因为该题目实际上要求的是时间复杂度为O(n)的算法。进一步研究题解后,发现有选手使用STL中的`nth_element`函数成功通过了所有测试点。本文将详细分析这一现象,并提出相应的优化策略。


文章目录

    • 一、手写快排最后两个测试数据超时了,预料之中的事情,因为这个题目考的应该就是`O(n)`的算法
    • 二、看题解有人用`STL`的`nth_element`过掉本题,我直接略过这种解法
    • 三、快读+快速排序(手写)+`-O2优化` (三者缺一不可)可以过掉此题,但`O(nlogn)`的算法不是预期的解法
    • 四、`vector` + `O(n)`的算法有些时候会超时
    • 五、换成数组 + `O(n)`的算法,通过了,而且时间很好看
    • 六、后记,`O(n)`的算法还需要好好研究,~~我自己没有看懂,自己其实一开始尝试写`O(n)`的算法了,但是总是出错,我也不知道为什么。而且对于函数中的while循环和递归函数,我都理不清楚出口的样子。先背过吧。~~ 已经弄明白了,讲解如下:
    • 七、教训


一、手写快排最后两个测试数据超时了,预料之中的事情,因为这个题目考的应该就是O(n)的算法


二、看题解有人用STLnth_element过掉本题,我直接略过这种解法


三、快读+快速排序(手写)+-O2优化 (三者缺一不可)可以过掉此题,但O(nlogn)的算法不是预期的解法

代码如下:

#include
#include
#include
using namespace std;int nums[5000005];void qsort(int left, int right){int x &#61; left, y &#61; right, mid &#61; nums[(left&#43;right)>>1];while(x<&#61;y){while(nums[x]<mid)x&#43;&#43;;while(mid<nums[y])y--;if(x<&#61;y){int tmp &#61; nums[x];nums[x] &#61; nums[y];nums[y] &#61; tmp;x&#43;&#43;;y--;}}//left, y, x, rightif(left<y)qsort(left, y);if(x<right)qsort(x, right);
}inline int read(){//快速读入 int x&#61;0,f&#61;1;char c&#61;getchar();while(c<&#39;0&#39;||c>&#39;9&#39;){if(c&#61;&#61;&#39;-&#39;)f&#61;-1;c&#61;getchar();}while(c>&#61;&#39;0&#39;&&c<&#61;&#39;9&#39;){x&#61;(x<<1)&#43;(x<<3)&#43;(c^48);c&#61;getchar();} return x*f;
}int main(){int cnt, k;//scanf("%d %d", &cnt, &k);cnt &#61; read();k &#61; read();if(k>cnt-1)return -1;for(int i&#61;0;i<cnt;i&#43;&#43;){nums[i] &#61; read();}qsort(0, cnt-1);cout<<nums[k]<<endl;return 0;
}

四、vector &#43; O(n)的算法有些时候会超时

说有些时候&#xff0c;是因为&#xff0c;运气好的时候&#xff0c;第五组测试数据就900多ms&#xff0c;刚刚好不会超时&#xff0c;但是有时候运气差&#xff08;我第二次提交这个代码就遇到了&#xff0c;由此看概率不低&#xff09;&#xff0c;就会超过1s&#xff0c;然后TLE

代码如下&#xff1a;

#include
#include
#include
using namespace std;void kthsmall(vector<int>& nums, int left, int right, int k, int* res){int x &#61; left, y &#61; right, mid &#61; nums[(x&#43;y)>>1];while(x<&#61;y){while(nums[x]<mid)x&#43;&#43;;while(mid<nums[y])y--;if(x<&#61;y){int tmp &#61; nums[x]; nums[x] &#61; nums[y]; nums[y] &#61; tmp;x&#43;&#43;;y--;}}//left<&#61;y<&#61;x<&#61;rightif(k<&#61;y)kthsmall(nums, left, y, k, res);else if(x<&#61;k)kthsmall(nums, x, right, k, res);else{*res &#61; y&#43;1;return;}
}int main(){int cnt, k;cin>>cnt>>k;vector<int> nums;for(int i&#61;0;i<cnt;i&#43;&#43;){int tmp;//cin>>tmp;scanf("%d", &tmp);nums.push_back(tmp);}int res &#61; 0;kthsmall(nums, 0, nums.size()-1, k, &res);cout<<nums[res]<<endl;return 0;
}

超时详情
在这里插入图片描述


五、换成数组 &#43; O(n)的算法&#xff0c;通过了&#xff0c;而且时间很好看

代码如下&#xff1a;

#include
#include
#include
using namespace std;int nums[5000005];void kthsmall(int left, int right, int k, int* res){int x &#61; left, y &#61; right, mid &#61; nums[(x&#43;y)>>1];while(x<&#61;y){while(nums[x]<mid)x&#43;&#43;;while(mid<nums[y])y--;if(x<&#61;y){int tmp &#61; nums[x]; nums[x] &#61; nums[y]; nums[y] &#61; tmp;x&#43;&#43;;y--;}}//left<&#61;y<&#61;x<&#61;rightif(k<&#61;y)kthsmall(left, y, k, res);else if(x<&#61;k)kthsmall(x, right, k, res);else{*res &#61; y&#43;1;return;}
}int main(){int cnt, k;cin>>cnt>>k;for(int i&#61;0;i<cnt;i&#43;&#43;){scanf("%d", &(nums[i]));}int res &#61; 0;kthsmall(0, cnt-1, k, &res);cout<<nums[res]<<endl;return 0;
}

好看的时间&#xff08;最多600多ms&#xff0c;十分nice&#xff09;
在这里插入图片描述


六、后记&#xff0c;O(n)的算法还需要好好研究&#xff0c;我自己没有看懂&#xff0c;自己其实一开始尝试写O(n)的算法了&#xff0c;但是总是出错&#xff0c;我也不知道为什么。而且对于函数中的while循环和递归函数&#xff0c;我都理不清楚出口的样子。先背过吧。 已经弄明白了&#xff0c;讲解如下&#xff1a;

2020年08月21日&#xff0c;通过循环不变量&#xff08;loop invariant&#xff09;想明白这个过程了。

while(x<&#61;y){while(nums[x]<mid)x&#43;&#43;;while(mid<nums[y])y--;if(x<&#61;y){int tmp &#61; nums[x]; nums[x] &#61; nums[y]; nums[y] &#61; tmp;x&#43;&#43;;y--;}}

这个while循环&#xff0c;最终的跳出循环时的条件是(y&#xff0c;并且保证了nums[left]<&#61;nums[y]<&#61;nums[x]<&#61;nums[right]&#xff0c;若yx之间有空隙&#xff0c;则空隙中的值作为nums数组索引下标所对应的所有nums中的值都是相等的&#xff0c;这是while循环能够保证的。

//left<&#61;y<&#61;x<&#61;rightif(k<&#61;y)kthsmall(left, y, k, res);else if(x<&#61;k)kthsmall(x, right, k, res);else{*res &#61; y&#43;1;return;}

这段代码讨论了k落在三个区间[left, y]、(y, x)、[x, right]的情况。对于第一种和第三种情况不多赘述。第二种情况&#xff0c;由于(y, x)中的值作为nums数组索引下标所对应的nums中的值都是相等的&#xff0c;因此*res &#61; y&#43;1;*res &#61; x-1;都是合适的&#xff0c;我在OJ上分别提交了这两个写法的代码&#xff0c;均AC了。


七、教训


  • 测试数据很猛的时候&#xff08;5000000的数据O(n)的复杂度&#xff0c;时间要求1s&#xff09;&#xff0c;尽量不要用vector&#xff0c;不但耗时&#xff0c;而且占用存储空间极大&#xff08;5000000的数据O(n)的复杂度&#xff0c;大概30多M的空间&#xff09;
  • 对于大数据的读取&#xff0c;万不得已用快读&#xff0c;其次用scanf&#xff0c;其实平常scanf就够用了&#xff0c;最好不要用cin
  • int数组开到5000000好像没啥大问题&#xff0c;再大了就不清楚了。

推荐阅读
  • 本指南从零开始介绍Scala编程语言的基础知识,重点讲解了Scala解释器REPL(读取-求值-打印-循环)的使用方法。REPL是Scala开发中的重要工具,能够帮助初学者快速理解和实践Scala的基本语法和特性。通过详细的示例和练习,读者将能够熟练掌握Scala的基础概念和编程技巧。 ... [详细]
  • 在洛谷 P1344 的坏牛奶追踪问题中,第一问要求计算最小割,而第二问则需要找到割边数量最少的最小割。通过为每条边附加一个单位权值,可以在求解最小割时优先选择边数较少的方案,从而同时解决两个问题。这种策略不仅简化了问题的求解过程,还确保了结果的最优性。 ... [详细]
  • 深入解析C语言中的动态规划算法:以背包问题为例
    本文深入探讨了C语言中动态规划算法的应用,以经典的背包问题为例进行详细解析。通过实例分析,展示了如何利用动态规划解决复杂优化问题,并提供了高效的代码实现方法。文章不仅涵盖了算法的基本原理,还讨论了其在实际编程中的应用技巧和优化策略,为读者提供了全面的理解和实践指导。 ... [详细]
  • 2012年9月12日优酷土豆校园招聘笔试题目解析与备考指南
    2012年9月12日,优酷土豆校园招聘笔试题目解析与备考指南。在选择题部分,有一道题目涉及中国人的血型分布情况,具体为A型30%、B型20%、O型40%、AB型10%。若需确保在随机选取的样本中,至少有一人为B型血的概率不低于90%,则需要选取的最少人数是多少?该问题不仅考察了概率统计的基本知识,还要求考生具备一定的逻辑推理能力。 ... [详细]
  • 题目链接: Caninepoetry问题概述:给定一个仅包含小写字母的字符串,允许将任意位置的字符修改为任意其他小写字母。目标是通过最少次数的修改,使字符串中所有长度大于1的子串均满足特定条件。本文详细分析了该问题,并运用思维与贪心算法,提出了一种高效解决方案。通过对字符串的深入解析,我们探讨了如何在最小化修改次数的同时,确保所有子串符合要求。 ... [详细]
  • 本文深入解析了Java面向对象编程的核心概念及其应用,重点探讨了面向对象的三大特性:封装、继承和多态。封装确保了数据的安全性和代码的可维护性;继承支持代码的重用和扩展;多态则增强了程序的灵活性和可扩展性。通过具体示例,文章详细阐述了这些特性在实际开发中的应用和优势。 ... [详细]
  • 本文探讨了在硬币找零问题中使用枚举法的具体应用。具体而言,题目要求将一定数额的零钱换成5分、2分和1分的硬币,并且每种硬币至少需要使用一枚。研究旨在找出所有可能的换法组合。输入数据为一行,包含一个在8到100之间的整数,表示待换的零钱数额。通过详细的枚举分析,本文提供了高效的解决方案,并验证了其在实际应用中的可行性和有效性。 ... [详细]
  • 第六章:枚举类型与switch结构的应用分析
    第六章深入探讨了枚举类型与 `switch` 结构在编程中的应用。枚举类型(`enum`)是一种将一组相关常量组织在一起的数据类型,广泛存在于多种编程语言中。例如,在 Cocoa 框架中,处理文本对齐时常用 `NSTextAlignment` 枚举来表示不同的对齐方式。通过结合 `switch` 结构,可以更清晰、高效地实现基于枚举值的逻辑分支,提高代码的可读性和维护性。 ... [详细]
  • 具备括号和分数功能的高级四则运算计算器
    本研究基于C语言开发了一款支持括号和分数运算的高级四则运算计算器。该计算器通过模拟手算过程,对每个运算符进行优先级标记,并按优先级从高到低依次执行计算。其中,加减运算的优先级最低,为0。此外,该计算器还支持复杂的分数运算,能够处理包含括号的表达式,提高了计算的准确性和灵活性。 ... [详细]
  • 本文总结了JavaScript的核心知识点和实用技巧,涵盖了变量声明、DOM操作、事件处理等重要方面。例如,通过`event.srcElement`获取触发事件的元素,并使用`alert`显示其HTML结构;利用`innerText`和`innerHTML`属性分别设置和获取文本内容及HTML内容。此外,还介绍了如何在表单中动态生成和操作``元素,以便更好地处理用户输入。这些技巧对于提升前端开发效率和代码质量具有重要意义。 ... [详细]
  • 本文介绍了如何在iOS平台上使用GLSL着色器将YV12格式的视频帧数据转换为RGB格式,并展示了转换后的图像效果。通过详细的技术实现步骤和代码示例,读者可以轻松掌握这一过程,适用于需要进行视频处理的应用开发。 ... [详细]
  • 贪心策略在算法设计中的应用与优化
    贪心算法在算法设计中具有广泛的应用,特别是在解决优化问题时表现出色。本文通过分析经典问题“买卖股票的最佳时机II”,探讨了贪心策略的基本原理及其在实际问题中的应用。通过实例分析,展示了贪心算法如何通过局部最优选择逐步达到全局最优解,并讨论了其在时间和空间复杂度上的优势。此外,还提出了一些优化方法,以提高算法的效率和适用性。 ... [详细]
  • AIX编程挑战赛:AIX正方形问题的算法解析与Java代码实现
    在昨晚的阅读中,我注意到了CSDN博主西部阿呆-小草屋发表的一篇文章《AIX程序设计大赛——AIX正方形问题》。该文详细阐述了AIX正方形问题的背景,并提供了一种基于Java语言的解决方案。本文将深入解析这一算法的核心思想,并展示具体的Java代码实现,旨在为参赛者和编程爱好者提供有价值的参考。 ... [详细]
  • 深入理解 Java 控制结构的全面指南 ... [详细]
  • 手指触控|Android电容屏幕驱动调试指南
    手指触控|Android电容屏幕驱动调试指南 ... [详细]
author-avatar
ke天天_809
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有