重拾程序设计题
今天是情人节,我竟然乖乖地去想明白一个题目。。。终于被我想明白了,也是比较高兴的,因为我昨晚对优化的第二种解法想不明白
昨晚跟某强闲聊,说在练习python题,计算:1+2+..+(n-1)+n的和,一开始以为他是不记得python语法,所以很久都弄不出来,老实说,裸打我也不记得,不仅python,C的语法我也挺模糊。。。
后来才发现他说是没想到怎么解决,也就是解题的逻辑,我就说人是怎么思考解决的,转化为计算机能懂的语言(编程),就行了。
之后就推荐他看看程序设计的题目,一开始不需要写,但是要想,而且尽力想明白(这个过程我知道是很辛苦的啦,过来人,苦闷、无聊、郁闷...不过坚持下去,逻辑思维能力、读题理解能力等肯定会有一个质的提升)。最后扔了两个题目网址给他:
(1)https://leetcode-cn.com/problemset/all/ ---- 职场人刷题多
(2)http://poj.org/problemlist ---- 学生党多
(今天才发现以前在里面刷了300+题目的杭电oj竟然不再对外开放了,有点伤感)
为了督促自己,我也希望这篇文章之后,坚持每天或者每周思考一些程序设计的题目。脑袋瓜不用真是容易用进废退的,然后买来的书不看也是劳民伤财的
####################### 上面都是废话
一、问题
临睡之前,我看了一条题,来自《算法竞赛入门经典》的第1章 例题18 开放式学分制(对应 UVa 11078),为什么选了这条题,因为题目够短
这里不给出源代码,只有伪代码,哈哈哈,因为我不记得怎么写了
我先简化下题目:
给出n个整数的序列:A0,A1,。。。。,An-1,现在需要从中找出两个整数 Ai 和 Aj(i < j),使得Ai - Aj 尽量大
【输入格式】
每组数据的第一行为整数的个数n(2 <= n <= 100000),以下n行,每行末一个绝对值不超过150 000 的整数
【输出格式】
输出 Ai - Aj 的最大值
二、问题分析
1、最容易想到的解决方法:两个for循环去解决
伪代码如下:
1 ans=A[0] - A[1] 2 3 for (i=0; i < n; i++) 4 for (j = i+1; j < n; j++) 5 ans = max(ans, A[i] - A[j]) 6 7 print ans
从A0开始,比较A1,。。。An-1 与A0 的差值;然后下一个循环,A1开始,比较A2。。。An-1 与 A1 的差值,不断重复这个过程。
要算的次数:(n-1) + (n-2) + ...+2+1= n*(n-1)/2
也就是时间复杂度为: O(n^2)
要是提交这个代码,TLE跑不掉(Time Limit Exceeded)
俺不纠结这个,大部分人都能想到的。然后看了第二种方法,书中写的特别拗口:对于每个固定的 j,我们应该选择的是 小于 j 且 Ai 最大的 i,而和 Aj 的具体数值无关。 这样,我们从小到大枚举 j, 顺便维护 Ai 的最大值即可。
一脸懵逼。。。不知所云,不明觉厉
2、优化算法 O(n)
我先举一个整数序列,就容易明白了:
-5 3 8 -2 8 9 -16 -1 -1
是不是人眼一看就知道 9 - (-16)是最大的,因为我们选了一个Ai 最大的值,也就是整数9,Aj 的值我们不管它大小,想想Aj固定的情况下,Ai 是不是应该越大越好?所以上面红字就说跟 Aj 无关。
对于每一个Aj来讲,假设扫描到 -16。我们是不是要比较 -16 之前 哪个Ai 是最大的,然后跟 Aj 做差,来获取一轮的 Ai - Aj。
然而这还不够,我们要维护一个在Aj 之前,也就是Aj-1,前面序列的: Ai - Aj-1 的最大值。例如,当遍历到-16这个数时,要知道 -5 到 9 这个序列(-5 3 8 -2 8 9)的最大 Ai - Aj
所以,每扫描一个A[j],应更新 A[i] 的最大值,且得到 A[i] - A[j-1] 的最大差值。每遍历一个数都能获得当前两个值的最大值,扫描到最后就是最终结果
伪代码贴下:
ans = A[0] - A[1] MaxAi = A[0]
for ( j = 1; j < n; j++) ans = max(ans, MaxAi - A[j]) MaxAi = max(A[j], MaxAi) print ans
如果还有啥不懂,欢迎交流~~~
希望自己也能捡回这个想题的习惯吧,这玩意还是挺有意思的,能锻炼:
(1)读题、理解能力 ——》理解需求(工作、或者别人交待的问题),理解清楚,这个是基础
(2)英文(有些题库是国外,纯英语) ——》 英文还是不能落下
(3)算法解题 ——》 工作问题或者生活问题怎么想的,怎么解决的思路
(4)优化能力 ——》 有基本解题思路,还要想想如何更优处理,不要TLE之类的,实际工作中就是节省时间和空间成本
时间类比成,跑一个代码结果一天都跑不下来的,想想就很郁闷>_<||
空间可以理解为,魂斗罗游戏设计只有100多k(https://www.zhihu.com/question/50076174/answer/1101330430),节省很多硬盘空间,短小精悍