一直很纠结算法的文章应该怎么写。最后觉得还是从最简单的level开始写吧,一开始就弄些重量级的,什么人工智能,机器学习的算法,还要有大量的数学以及优化的知识,小白们估计会很郁闷,当然我也不一定能做出来对吧。
我计划每题给出两种语言的解决方案,一种静态语言,一种动态语言。
我选择C语言和Python,本来考虑Java,但是篇幅有限,有兴趣的朋友自己试试。
LeetCode 561. 数组分区I(Array Partition I)
问题描述:
给定一个包含2n个整数元素的数组,将其拆分成n个仅仅包含2个元素的小数组,如(a1, b1), (a2, b2), ..., (an, bn),求出所有min(ai,bi)的和。
注意:
- n取值范围是1~10000;
- 数组中元素的取值范围是 -10000~10000;
C语言实现:
题目说拆分成小数组,我们不一定真的要这么拆分,多观察多思考还是很有必要的。
第一种方法:
思路是先排序,然后求排序后的数组中所有偶数下标的和。
我们这里使用库函数qsort(),除非十分必要,否则不建议大家自己实现排序算法。虽然排序算法原理大家已经很熟悉,但是要是让自己写,还是要花一些时间的,而且你花费的这部分时间造出的车不一定有库提供的好用。
可以看到,这个解决方案虽然实现简单,但是效率却不是很理想。
第二种方式:
按照题目的要求,可以知道,数组的最大长度不会超过20001,因此对于这道题,我们可以用空间换时间的办法,建立一个长度为20001的数组buf,然后遍历给定的数组nums,其元素的值作为作为buf的对应下标,来统计这个值在nums中出现的次数。
说起来比较拗口,这里举例,假设nums=[1,2,2,7,2,9,1,4],遍历nums后填充buf后,buf中的内容如下:
大家可以注意到,这实现了nums的“排序”,只是排序的值变成了buf数组的“序列号”。
这样处理后,再通过对计数值的处理就可以获得最终的sum。这里重要的是理解step变量的作用,它是来控制指向的最小值得位置和状态。例如 10001这个点记录了1在nums中出现了2次,那么很自然我们可以拆分数组为[1,1]; 然后10002这个点表示2出现了3次,那么很自然可以拆分出[2,2],和[2,x],这个x一定10002右边最近的那个,即10004,这个时候step被设置为0了,表示,10004中的一个要拿来给前面的10002组成一对。
代码如下,这个思路可能有些不太好理解,建议大家对照上面的图慢慢琢磨,有问题可以在下面提问,我会及时解答。
可见,这个解决方案的效果还是不错的。
python实现:
排序,切片,求和。一行代码足矣。
貌似python这个运行时间很有问题,相同的代码我试着提交了几次,每次这个时间都不一样,不过不同也是可以理解的。