1.动态规划:
动态规划最主要的是问题的子问题是最优解,整个问题便具有最优解。
2.最长上升子序列:
最长上升子序列的目的是找到一串数字中最长的递增子序列,相对于麻烦的是,子序列可以是不连续的。所以,我将子序列的长度从0开始到数组的长度,每一次循环,i都指向了选中长度的末端,j从0遍历到i-1
len数组存放的是该点对应的最长子序列的长度。
第17行,遍历a[0]到a[i-1]的数,如果有小于i并且有长度更大值的便写入(小于i是因为要求上升子序列,i作为子序列最末端的元素自然要最大,也不能等于i,)
第20行,是将末端元素i的长度加进去。
maxsize是在j遍历完成后,存储现在子序列长度的最大值。
从整体来看,因为,i,j都是从0开始,子序列的长度也是从0开始。那么每一次的遍历,都会基于上一次的最优解。便可以将最优的解存入len数组。
3.最长回文子串:
与最长上升子序列不同的是,回文字串是要求不断开的,所以在这里就不用让子序列的长度从0到n。
这里,我们让i从0到n,j在0-i的范围内进行遍历操作。s存放的是字符串,maxsize存放的是最长回文字符串的长度。dp是数组是表示i,j所指向的对象以及之前的数是否相同是否相同,相同为1,不同为0.
第18行,当i-j小于2时,长度为1.所以,如果s[i]==s[j]他们的长度就为1。
第21行,要使dp为1,必须是当前的i,j相等,并且中间的字符串也要相等。例如,如果i=5,j=1;
如果要使dp[1][5]=1,则dp[2][4]也要为1,而dp[2][4]为1的前提是dp[3][3]相等,s[2]和s[4]相同。所以这样的情况下,dp[j][i]为1,j-i一定为回文字串。
所以第22行,判断的前提是dp[j][i]==1,并且maxsize<i-j+1,(比如2到4,它的长度是4-2+1)
4.最长回文子序列
与最长回文字串不同的是,最长回文子序列也可以是不连续的,所以我们同样使子序列的长度从1到n,下图中,i为子序列的长度。j为子序列开始的位置,i+j为子序列结束的位置。
len存储的是子序列的最大长度。
有如下3种情况
(1):当s[j]s[i+j]时,子序列两端字符相同(第25行)
(1):i1时,子序列只有两个字符,所以长度为2(第28行)
(2):当i>1时,此时子序列的长度为len[j+1][j+i-1]+2,(+2的原因是)
(2):当s[j]!=s[i+j]时,首尾两字符不等,此时在len[j][i+j-1]和len[j+1][i+j]中选择最大值,然后再在最大值的基础上加上首位两个字符的长度。
最后,最大值一定是在len[0][n-1]中,代表字符数组的遍历从0开始,最大有n个
5.石子合并
初始化的时候,因为这是环形的,最后一堆石子是和第一个靠近的,所以num[n]至num[2n-2]将数据再次录入。
num[]数组存放没堆石子的数量,t代表已经加入的堆数,初始值为1,i指向开始处,j指向结尾处,k指向i与j的中点。
此处用k指向中点是为判断,i-k,与k-j之间的最优解(实际上是一个向左合并或向右合并的判断)。
第33行,num[j]-num[i-j],是因为在t相同的情况下,i+1代表前移,自然要将新加入的值和去掉的值进行相减,才能保证数据的正确