前段时间找工作面试的时候遇到了一道算法题,题目的内容大致是这样的,

一个数组,将其分为两部分使得两部分的和差最小。

面试的时候没有想出很好的解决方法,后来回家后仔细的想了想发现问题其实不是那么复杂。下面说一下自己的思路,

既然是分解成两个子数组,并且两个子数组之和差最小,那么一个数组的和就应该尽量的靠近原数组的和的一半,所以这时候的问题就转化成了下面的问题

一个数组a[n],找出i个元素,并且i<=n,使得这i个元素对应的和尽可能的靠近 sum(a[0]..a[n-1]) / 2

相信很多人这时候都会觉得这个问题有点眼熟,是的这个问题其实就是我们非常熟悉的背包问题,如果你对背包问题理解的比较透彻的话,很快的就能写出对应的代码,无论是使用递归还是动态规划。

写这篇文章的主要目的并不是讲解这道题本身应该怎么解决,而是希望将自己从这道题得到的启示记录下来。无论是生活中或者工作中都会遇到很多问题,这些问题或许看起来很复杂,但是如果你仔细思考,你会发现它其实都是你之前遇到的或者已经有比较成熟的解决方法的问题的变种。这就需要我们能够发现问题的本质,对问题进行一定程度的抽象。说到这又想到了之前工作中遇到的一个问题,

之前某个项目主要是接收上传的文件并且记录元数据,也就是那个分片上传完成了,开始的时候各个分片大小是固定的,当时的技术方案通过在redis中记录了每个分片的对应的bit位,很好的解决了元数据记录的问题。但是后来有新的需求,分片的大小会改变,并且重传的时候可能和之前的分片有重合,比如说第2个分片是1000-2000,第三个分片传来1500到2500,这时候就需要修改当前的元数据记录方案。

相信大家看到这个问题的时候会第一时间想到对各个分片的大小进行计算,然后和之前上传的数据做对比,比较各种边缘情况。这样子做本质上是没有问题的,但是由于需要考虑到各种边缘情况给编码以及测试都带来了不小的难度。既然都是记录元数据的方案,那么新的方案能否向之前的靠拢呢?答案是肯定的,两者之间的本质问题,就是前者分片大小固定,不会出现重叠的情况,后者分片大小固定存在重叠的情况,我们需要做的是将后者转化为前者。有了这个思路,我们可能会想到将不固定大小的分片在逻辑上分成n个大小固定的分片,然后分别记录这n个分片的元数据,同时约定分片大小必须是固定分片大小的整数倍,比如我们约定这个固定大小分片为x,那么上传的分片大小则为n*x,就可以将原本复杂的问题解决了。

除了上面提到的两个例子,工作中其实还有其他很多这种例子,比如我们耳熟能详的设计模式。我们在解决某些特定场景的问题时,往往会朝设计模式靠拢,比如当我们需要限定某个类的实例化的时候,往往会使用单例模式。虽然很多人觉得设计模式过于模式化,但是很多情况下将问题抽象为已有的设计模式,很大程度上帮助我们实现更为优雅的代码。

总而言之,当我们遇到问题的时候,应该多思考,很多时候只要你做到适当的抽象,问题往往会迎刃而解。。