一般思想
1、将问题简化,从比较简单的情况开始分析,比如1个元素情况,2个元素情况,3个元素情况,不断增加,寻找规律,这样有利于发现规律,从而解决问题,并且也有利于处理边界情况。比如编程之美1.11、又如送货站选址问题、1的个数问题等都可一通过逐渐的分析加以解决
2、从比较简单的例子,模拟程序运行过程,比如二分查找,可以使用4个元素的例子,模拟查找过程,总结判断条件等。
3、拿到一个问题,首先看看能否依照题意通过循环直接求解,能否分治求解,分治求解关键的是两部和合并后如何求解,例如距离最近的点问题,归并排序问题,数组和最大问题(编程珠玑上的解法)这和使用递归的解法很相似,分治法通常采用递归解决问题、如果是组合优化问题,优先考虑动态规划或贪心求解
4、关于“2”,从中国古代的阴阳,到辩证唯物主义的正反面,“2”在哲学上具有重要的意义。对计算机来说更是如此:计算机中的二进制;分治法通常将问题分成2份;折半查找也有2;很多问题要么分成两面来看(二分查找);要么分成两个子问题(分治法);要么扣其两端,比较中间(链表相交使用2个指针、找符合条件的两个数编程之美2.2、编程之美2.21等问题都很2有关);还有数据结构二叉树;分析问题时,查其两端,使用两个指针,可能会给问题的解决带来诸多方便,再比如可以用两个stack来实现一个queue。
关于动态规划
1、如果一个问题涉及到求最优的解,就可能会试用动态规划来求解2、动态规划关键要给出递归求解的方程,再看看递归过程中是否重复了某些求解过程,将这些求解过程预先从底向上的求解出来并保存好,以后直接使用。
3、如果能画出保存数据的矩阵或数组,程序基本就清楚了,由于是自底向上求解,在求解i问题时,使用到i-1的结果,也就是访问数组或矩阵的i-1位置
4、动态规划常常设计到组合爆炸问题,一般不要考虑如何组合来解决问题,因为这样通常不利于思考程序如何设计,而应该考虑如何循环并设置保存计算结果的矩阵,通过i-1到i的迭代来解决问题,组合虽然是问题的直接表达,但不利与程序的设计,因为程序最终是通过若干个循环来完成的。
5、保存数据的矩阵或数组通常比处理的数据要多一行(列),因为第0行(列)是初始值,用来计算i=1(0)时,用到i-1数据
*6、如果用到循环求部分和问题,常常会导致增加N倍的复杂度,这时可以利用以前求和的结果+当前元素来减少循环的次数,从而降低复杂度,例如:送货站选址问题、子数组最大和问题等等,这一点很有价值。
关于递归
1、如果递归前对全局或引用变量++了,那么如果递归后希望该变量恢复到以前的值,那么递归后--该变量,例如求树的高度,就采用了这种策略。
2、递归使用了函数调用的结果,我们不用关心结果是如何得到的,直接使用就是了,但其实不然,实际的计算过程都是在递归后面真正的计算处理过程完成的,而递归得到的结果常常有利与后面的计算过程,典型的问题是求最近两点的距离问题。
3、递归常常带来效率问题,比如求斐波那契数列问题,循环的速度要远高于递归的速度,递归的效率和栈的规模都比较限制递归问题能够处理的问题的规模。
常识问题
1、数组中间的位置是(start + end) / 2,分治算法通常处理F(start, (start + end) / 2)和F((start + end) / 2 + 1, end)两个问题,而折半查找,因为已经比较了中间的元素,因此start = middle + 1;或end = middle - 1,start = end时处理只有一个元素的情况,需要特别注意
2、数组中元素的个素为end - start + 1个
3、给定一个数要求各位通过模10来获得,要取十位以上的数据通过除10来处理,
例如123,123 % 10 = 3; 123 / 10 = 12