前言
递归代码简洁,有着高效的执行效率。本文通过算法–最长连续递增子序列,来锻炼分析并拆解问题,再将拆解出的相同子问题进行递归改写。
一、最长连续递增子序列
二、循环与递归
1、双指针循环
// 最长连续递增序列。
public class FindLengthOfLCIS {
/*
target:寻找最长连续递增子序列。
如何确定连续子序列?用指针确定起点和端点即可确定一个子序列。
如何保证递增?保证前驱小于后继,根据传递性,那么该子序列为递增子序列。
如何求最长?通过一个端点指针减去起点指针,即可得到一个子序列长度,用一个变量记录最长长度,在寻找满足条件的子序列过程中,不断更新它即可。
*/
public int findLengthOfLCIS(int[] nums) {
// 初始化起始指针位置。
int begin = 0, end = 1;
int max = 0;// 初始化最长子序列长度。
int gap = 0;// 子序列的长度。
while (end < nums.length) {
// 不递增的情况。
if (nums[end] <= nums[end - 1]) {
// 更新最长子序列长度。
gap = end - begin;
if (max < gap) max = gap;
// 更新下一个子序列的起始节点。
begin = end;
}
// 递增 或者 不递增,都需要往后遍历。
++end;
}
// 当循环结束之后,还有最后一个递增子序列需要比较一下长度。
gap = end - begin;
if (max < gap) max = gap;
// 返回最终找到的最大子序列长度。
return max;
}
}
2、双指针递归
// 一题多解,开拓视野。采用简洁的递归来完成。
class FindLengthOfLCIS2 {
/*
target:寻找最长连续递增子序列。
如何确定连续子序列?用指针确定起点和端点即可确定一个子序列。
如何保证递增?保证前驱小于后继,根据传递性,那么该子序列为递增子序列。
如何求最长?通过一个端点指针减去起点指针,即可得到一个子序列长度,用一个变量记录最长长度,在寻找满足条件的子序列过程中,不断更新它即可。
*/
public int findLengthOfLCIS(int[] nums) {
return findLengthOfLCIS(nums, 0, 1);
}
/**
* 双指针 + 递归,递归完成最大子序列长度的判断与获取。
* @param nums 原数组。
* @param begin 起始指针。
* @param end 结尾指针。
* @return 最长子序列长度,当然递归出口返回最后一个子序列长度即可。
*/
private int findLengthOfLCIS(int[] nums, int begin, int end) {
// 递归确定最长递增子序列。
while (end < nums.length) {
// 子序列确定以后,就开始递归比较谁是最长子序列。
if (nums[end] <= nums[end - 1]) return Math.max(end - begin, findLengthOfLCIS(nums, end, end + 1));
// 还未能确定当前连续递增子序列。
++end;
}
// while正常结束,递归也结束了,返回最后一个连续递增子序列长度。
return end - begin;
}
}
总结
1)问题拆解,双指针问题。
2)独立相同子问题,可进行递归改写,高效执行。