88. Merge Sorted Array
这是Leetcode面试榜单Top150第一题,难度系数为容易。数据的存储结构为数组,第一个数组前m个元素已经排好序,后n个元素为0(视为占位元素),第二个数组也已经排好序,恰好n个元素。要求把第二个数组元素合并到第一个数组里并且保持合并后的数组m+n个元素排好序。问题详情请移步:原题传送门。
充分理解问题以后,难免迫不及待地想操刀码码,然后点击运行通过,在点提交,然后看看获得通过,再看看Leetcode给出的报告,运行时间和空间复杂度是多少,优于所有的提交的多少个百分比。如果击败了所有的100%则心底一阵狂喜,脸上还要按捺住不要忘形的样子,如果占比很低,脸上也要故作平静,掩盖心底的悲伤成河。如果你也和我一样一样的,请对自己慈悲一点,这并没什么大不了,谁还不曾是个宝宝呢。
刷题既是一个终点,也是一个途径。我们刷题可以是为了获得LeetCode给的结果报告,也可以是为了刷题本身,完全感受刷题时的每一个时时刻刻,为了真实感知生命和生活的存在。带着觉知之光的每一次思考和引发的行为,会因此变得神圣起来,敲代码的时候就敲代码,脑子里不用想着待会点击运行会怎样,提交后又会怎样。运行时报错就看错误的提示,提交报告出来就看报告。不再因方才不仔细或者思虑不周坠入懊恼的藩篱,也不着急于冲入之后才发生的未来牢笼,便能感受此时此刻,品味题目的美感和可心,享受这份美好的喜悦之情。
由于先前不知什么时候,或者看过类似的算法设计,或者数据结构课上老师教授残留的印记,经过读题理解问题时,脑子里闪过合并时从后往前写入第一个数组(占位空间在数据后部)。加上合并两个有序数组又是比较常见的,写数组元素的索引从第一个数组第m+n个元素位置开始向0移动,第一个数组用一个读索引p1从第m个元素开始往0遍历,第二个数组也用一个读索引p2从元素n向0遍历,每一次p1或者p2对应两个数组中的元素较大的写到第一个数组的p位置,同时往前移动写索引p和两个读索引p1和p2之一。
这是凭记忆和经验的冲动型刷题,无所谓好坏,但如果仅仅止步于此,那么这次刷题活动仅仅重新复习了原先已经了解的知识内容,让记忆更清晰,更牢靠,顺便修复一下岁月流逝而遗忘,模糊的部分。远没有对提升我们的认知层级,挖掘更深刻的洞见提供创新。那么如何才能在自己已经知道的牢笼中活动开了以后,找到认知的边缘,碰碰壁,摸索寻找墙上的门窗,从认知的樊笼中越狱?
头脑风暴是一个有力的工具,如何有效进行头脑风暴,使之有可能产生尽可能多的积极意义,奔驰SCAMPER工作法是个值得了解的思维工具,通过把原有流程,各个组成要素尝试做替换S,组合C,适配A,修改篡改M,挪作他用P,消减E,重排翻转R一系列的操作,可以枚举若干的可能性。
比如本题,在我们搞出倒过来遍历两个数组,比较大小,从第一个数组尾部向前倒着写入的解法之后。首先可以尝试一些替换,比如不是倒着遍历而是从左到右顺着遍历两个数组会怎样,可不可以有此解法,倘若合并操作和排序操作改做两个独立的步骤,又有怎样的解法?合并完,数组排序的方法又有很多种可以适配哪种?除了先合并再排序,修改成逐个元素插入排序(第一个数组已有元素已经有序),...等等。
当我们搞出多个解决算法之后,再来比较分析它们,算法的时间复杂度,和空间复杂度一下子生动了许多。另外,对数组这种容器,似乎可有更通用的抽象,比如读写,遍历,排序,比较移动删除元素等等。
另外对于数组这种基本数据结构在算法中三大的范式,分治,递归,动态规划,各有各的适应特点。