1. 首先是条件的提取;
2. 然后是寻找解决方案;
3. 做完了一定要验证;
4. 扩展:
a. 列出所有你解决方案中用到的条件;
b. 问自己一些问题,仔细思考你现行的解决方案中有没有做重复或多余或疑似复杂了的步骤;
c. 如果有重复步骤,尝试在原有条件不变的前提下,优化解决方
最近,在波利亚GG的谆谆教诲下,在pongba同学的循循善诱下,在TopLanguage的今天我们思考系列的热情引导下,我终于痛下决心开始琢磨所谓的科学思考问题的方法。对大部分人而言,解题不是终极目的,只是希望在解题中培养的思考问题的方式能够广泛的应用到其他领域。我依然觉得,思维这个抽象的可怕的东西,本质上还是个体化的,要因人而异,很难找到一招鲜吃遍天的套路。但其中,一些共性的东西还是可以抽取出来,一起琢磨一起讨论一起研究,并规范化科学化。大师的书pangbo的文章和大家的讨论提供了足够的参考素材,在这里我只是写我自己这些日子来的一些实践和思考。我混了20多年,还是一个解题白痴,可以想见,这段日子的集训也不会有质变的效果,所以写下一个beta,作为不成熟的挡箭牌。在今后的日子里,我会继续的思考和实践,希望有一天,我可以有勇气在后面加个v1.0。。。
我一直以为,要想解决问题,除了所谓耐心勇气等人性方面的因素外,至少还需要两方面的储备。一面谓之硬件,指的是基本的知识。比如说你要设计一个算法,基本的复杂度分析,分治法,二分法之类的知识应该需要储备起来;如果你要设计个软件架构,基本的模式,操作系统的原理,交互接口的设计也应该了解一些。不要以为自需要很小的一点知识库,就可以像原子弹似的衍生出无限的能量,自己造轮子做汽车的生产方式,已被这个高效的社会淘汰了。牛顿GG很早就教育我们要站在巨人的肩膀上才能站的高看得远,而如《费马大定理》中描绘的一样,怀尔斯如果不是充分了解所有前人的思路深刻掌握许多高精尖的数学方法的话,从最原始的公理开始,我想再送他100年寿命估计也搞不定费马大定理。所以,一个人只有拥有了足够丰富的知识后,才有可能混得和机器猫的口袋似的,要啥有啥。。。
另一面谓之软件,指的就是解决问题的基本思维。在《Why Programs Fail》中我了解到,调试这种貌似依靠经验和灵感的活也是可以有章可循的。与之类似,所有貌似只能靠灵感喷涌来搞定的问题,也不会是只有咣当咣当拍脑袋才能获得解决思路的。我们需要信赖灵感,但很多时候,也可以不依靠灵感。我们有了足够的知识储备和运用知识的经验后,就像骑上了匹宝马良驹,有了一马平川奔向目的地的能力,但是没有良好的驾驭,南辕北辙了,就算是汗血宝马估计也无奈了。。。
从这段时间的实践来看,波利亚GG的解题框架是极具推广性的。不但在解题上会有效果,尝试推广到软件设计甚至其他方面上,也是可以行得通的。主要实践原料的来源,除了TopLanguage里面的一些题目外,还有来自《编程之美》的习题和高大爷仙书上的一些经典算法。在我这里,波利亚GG的框架被我抽取成下述样子,不过强烈建议自己去阅读原著,抽取属于自己的框架:
1. 首先是条件的提取。对于题目而言,就是把题设的条件一部分一部分抽取出来,然后牢牢把握住未知量,从始到终,同时,要对已有已知量是否能导出未知量有个评估。对于其他问题而言,比如软件设计,条件就是做这个项目的一些要求和约束,未知量就是需要做到的效果,评估就是在这样的条件下能不能做到需要的效果。这个问题说起来简单,把握起来却不容易。我在自己做题或者给别人出题的时候,我经常会发现,在做的过程中很多条件被遗忘了,或者没有被充分利用到。 pangba的一个实践方法很好,就是把所有的条件都一条条写下来,并尽可能的扩展开,毕竟,不是每个人都是欧拉。一个例子,可以看这里。。。
2. 然后是寻找解决方案。摊开了讲,就复杂了,想了解,看书算是最好的方式。简单说,先要对题目进行归约,努力回想你做过的类似的题目。有一招就对题目转述,我觉挺好的方式,有的东西说一下就更明晰了。比如,题目是找一组一维点中的最大距离。改下题,说找一组有序点的最大距离,问题就明晰多了。先变有序,再找距离。而从思索的角度上看,从条件开始试错,或从未知量开始倒着做都是可以尝试的方式。有的时候,你需要把特化考虑问题,即考虑特殊的情况类推出普遍情况,这种方式我们常用。还有一种是泛化,把特殊的问题变普遍了,不知不觉中也会常用。比如这里的第二题,把那几个恐怖的数字抹平成了N,问题就清晰了。。。
3. 做完了一定要验证。从小到大数学考试,我从来都是做完了就算,很公平,也被无数次惩罚了。验证可以是不完备的,用基本的逻辑和特例来验证一下,也可以是完备的,用数学方法来证明。说这个就想起测试,写代码的时候,很多自以为完美无缺的逻辑,在测试下都显得脆弱不堪,所以无论如何,验证是必需的,这个懒,在任何时候,还是不偷的好。。。
4. 扩展。前面说的都很简单,客观原因大牛们已经写了很多了,主观原因我很懒。因此,这一点决定多写一点,理由是感触多些。扩展,在我的定义下,有两层意思,一个是对原有方法的改进,另一个是尝试挖掘一下为可能的问题做准备。两者在实践上是一致的,因此归为一点。当你完成并验证了某个题或某件事,你还需要进一步的反思和改进,这就是我所谓的扩展,实践包括以下几个步骤:
4.a. 列出所有你解决方案中用到的条件。这个条件和题设的条件可能是不一致的,因为你在具体解决过程中可能加入了有形或无形的约束。比如,打印一个树的前序遍历。很有可能,你在解决这个问题的时候默认这个树是以最常见的左右链表的形式保存的,这个过程中,你就多添加了一个约束,有没有想过,如果你用穿线树的格式存,解决方案就完全不一样了。这样的条件列举还是蛮不容易的事情,很多隐藏的条件(约束)不容易被挖掘出来,要努力的多想尽量的多列。比如做比较排序的时候,你有没有发现,你可能添加了一个无形的约束,就是每次都是键和键直接比较,想一想,去除掉这个约束视野会更开阔的。
4.b. 问自己一些问题,仔细思考你现行的解决方案中有没有做重复或多余或疑似复杂了的步骤。比如,KMP算法就是在降低一般算法的重复;再比如一题,找一个N位二进制中的1的数目,如果你写了一个O(N)的算法,仔细想想你做了什么多余的工作呢;还比如,冒泡算法作为一种交换的排序算法,有没有做什么疑似复杂的操作呢。
4.c. 如果有重复步骤,尝试在原有条件不变的前提下,优化解决方案。比如,上面所提,找1数目的题目,你可以想到既然是找1的数目,那么应该能做到O(M)的算法,其中M是1的个数。再继续,能不能够用一些其他策略,比如时间换空间,把算法复杂度降到常数级别呢。想知道答案,可以查看一下《编程之美》,呵呵。
4.d. 如果在原有条件上没有继续优化的空间,那么试图改变一些条件试试。这个条件如果是你在设计执行方案的时候添加进去的,那么这就是一个对已有的优化;如果,这个条件是题设的,那么就是对这个未知的扩展尝试。
4.e. 在改进的过程中,你可能引入了新的约束,更新约束列表,继续尝试上述步骤。
最后,写个例子,我尝试按照这个思路把高大爷仙书第三卷的插入排序部分串了一下,本书的其他部分我也实践了一下,但还没有完全一体化,如果有兴趣不妨尝试一下^_^。
a. 根据打扑克牌得来的心得,设计了一个基于顺序数组存放的最最普通的插入排序,经验证正确,至此,上述1~3步的工作完成。
b. 提取了一下约束,包括:存储空间是连续的静态分配的;在排序的过程中,数组的前半部分是有序的;每次插入一个新元素的时候,并不能保证一定把这个元素插入到了最终位置;是基于键值比较来确定大小关系的;没有使用过多的额外空间。
c. 问自己一个问题,能不能提高插入的速度?很自然我们想到了二分,于是有了二分插入。
d. 再继续,发现在目前条件下没有太大改进空间(别说用斐波纳契分...),于是考虑改变一些条件。最简单的,如果我不保证前半部分有序,我能怎么做。于是有了二路插入,将点定在中间,减少移动次数。
e. 如果你和shell一样有更多的硬件储备(前面提到的,有时候是需要硬件储备的...),你会联想到去掉前半部分有序,可以运用局部化和分治的思想,于是就有了Shell排序。
f. 如果,你开始问自己的问题是,能不能减少数据移动提高速度?一个答案是,改变的顺序存储,变链表,于是有了链表插入。
g. 能不能更快?于是,在原有基础上改变,我们添加一个哨兵指针,放在上次插入的位置。
h. 不要忘了,更新一下列表,我们发现添加了一个链式存储的约束,这个约束下,二分不能使用,查找速度降低。
i. 自然而然,我们问自己,能不能查找又快又少移动呢?继续改变条件,还是变数据结构,于是有了树插入(又见硬件储备...)。
j. 想想,还有没有什么条件没有改变过。很显然,基于键的比较没变过,不能保证将元素插入到最终的位置也是一个。联想起来,能不能不基于比较基于计算,能不能尽量一次到位这样可以减少移动次数。如果足够幸运,你可以想出基于地址的排序。
k. 其实,还有很多条件没有变过或可以继续变,有兴趣就继续下去吧:)。。。
分享到:
相关推荐
- **解决思路**:此类问题通常是由于信号覆盖不佳造成,终端本身没有问题。 3. **切换不到4G网络问题**: - **问题描述**:通信协议性能差,长时间无法切换至4G网络。 - **问题分析**:4G网络信号在问题发生前...
### 背包问题九讲2.0 beta1.2 #### 1. 01背包问题 **1.1 题目** 假设我们有N件物品和一个容量为V的背包。每件物品都有自己的费用\( C_i \)和价值\( W_i \)。目标是选择一些物品放入背包,使得总价值最大,同时不...
QQ2005beta2协议分析是一个针对腾讯QQ在2005年发布的第二个测试版本的通信协议进行深入...这份资料对于理解早期即时通讯软件的设计思路和技术实现具有重要价值,同时也为现代即时通讯应用的开发提供了一定的历史借鉴。
5. **参与社区交流**:与其他开发者交流,获取最新更新和解决问题的经验。 总结,"Lemon v1.2 Beta src"不仅是一个评测系统,也是开发者学习和研究软件测试策略、工具和实践的宝贵资源。通过深入源码,我们可以更好...
在解决问题的过程中,开发者应该遵循以下步骤: 1. **复现问题**:首先在本地环境中重现问题,以便进行调试。 2. **定位问题**:通过日志分析、断点调试、代码审查等方式找出问题的源头。 3. **修复问题**:修复...
5,自己构造大部分的基本数据结构,list stack等等,不做边界判断(省去if else判断),一旦边界异常,正好可以发现错误解决问题. 6,二维数组一维化(加速寻址时间)。 7,提炼精简代码,代码量缩减到2100行。
这一创新技术的出现,不仅解决了两大操作系统之间应用不互通的问题,也为WM用户提供了更丰富的软件资源。 Windows Mobile 6.0是微软推出的一款面向智能手机的操作系统,以其强大的办公功能和良好的硬件支持而受到...
【天涯网购 v1.0 Beta】是一款...同时,通过调试和修复源代码中的问题,可以提升自身的编程能力和解决问题的能力。而对普通用户来说,了解源代码可以帮助他们更好地评估软件的安全性和稳定性,从而做出是否使用的决定。
这些资料反映了开发者在解决具体问题时的思路,也可能包含了一些优化技巧和最佳实践。 4. **资料整理**:这个文件夹名可能意味着包含了一些组织有序的学习材料,比如教程、常见问题解答(FAQ)、错误日志等。这些...
动态规划是一种解决问题的策略,通过将大问题分解成子问题,并存储子问题的解决方案,避免重复计算,以达到高效求解的目的。它广泛应用于诸如最短路径、背包问题、最长公共子序列、矩阵链乘法等经典问题。在PKU的...
其次,Java毕设或毕业设计通常要求学生运用所学知识解决实际问题,因此,javapms可能是某个学生的毕业设计作品。在这样的项目中,学生通常需要实现完整的业务流程,包括用户登录注册、权限管理、任务分配、进度跟踪...
"javapms-1.2-beta.zip" 是一个压缩包,包含了Java开发的PMS(Project Management System)的源代码,版本为1.2的测试版。...通过阅读源码、运行项目和理解文档,可以极大地提升个人的编程技能和解决问题的能力。
这样的资源能有效节省学习者的时间,提高他们分析和解决问题的效率,尤其适合进行毕业设计、毕业论文或课程设计时参考。 【标签】进一步明确了这个资源的应用场景。"毕业设计" 和 "毕业论文" 指出这可能是一个适合...
源码是软件的心脏,通过分析源码,我们可以发现wtag v1.0 Beta的设计思路、编程模式以及性能优化策略。在深入研究前,建议先熟悉所使用的编程语言,可能是JavaScript、Python、Java或C#等。对于初学者来说,理解源码...
- **故障排查:** 遇到问题时的解决思路。 - **错误日志分析:** 查看系统日志以诊断问题。 **7.6 访问磁盘** - **分区与格式化:** 磁盘分区的基础知识。 - **挂载与卸载:** 文件系统的挂载与卸载操作。 #### ...
作为管理员,我们需要关注日志记录和错误处理,以便及时发现和解决问题。 总的来说,WebForum v1.0 Beta1是一个优秀的开源论坛系统,不仅提供了基础的社区功能,还为开发者提供了广阔的二次开发空间。通过深入研究...
而“另类其它”标签可能意味着该上传类具有独特的设计或者不同于常规的实现方式,它可能提供了一种新颖的解决文件上传问题的思路。作为源代码,它不仅适用于学习和研究,也可以在各种应用场景中实际部署。 “源代码...
此外,活跃的社区提供了丰富的教程、插件和解答,帮助开发者解决实际问题。 在实际应用中,通过结合UIkit 3.0 Beta的js和css文件,你可以快速搭建出具备Apple风格的网站,实现美观、高效的界面设计。无论是个人项目...
总的来说,esoTalk v1.0.0 beta 2是一个创新的论坛解决方案,它的出现为社区建设带来了新的思路。如果你正在寻找一个简单易用,又具有高度可定制性的论坛系统,esoTalk绝对值得你考虑。通过深入学习和理解它的源码,...