描述
给你一个n,,和一个长度为n的数组,在不同时选位置相邻的两个数的基础上,求该序列的最大子序列和(挑选出的子序列可以为空)。
方法一
思路
- 枚举,递归,回溯;
- 所求子序列集合要求各个元素之间互不相邻,假设所给数组为arr,对于下标为index的元素总共两种选择,将其放入子序列集合或者是不放入,那么便存在如下递推公式:
f(n-1)表示不要当前元素,f(n-2)表示将当前元素纳入最大子序列集合中,n需要大于等于3,
而当n = 1时,
当n = 2时, - 故可以依据上述递推公式,递归计算不相邻最大子序列和。
- 代码如下:
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * 计算 * @param n int整型 数组的长度 * @param array int整型一维数组 长度为n的数组 * @return long长整型 */ public long subsequence (int n, int[] array) { return getMax(0,array); } private long getMax(int start,int[] array){ if (start >= array.length){ return 0; } // 子序列中包含array[start]的最大子序列和 long taken = 0; // 子序列中不包含array[start]的最大子序列和 long untaken = 0; // 不包含 untaken = getMax(start + 1,array); // 若array[start] 小于等于0,则直接不要该数 if (array[start] <= 0){ return untaken; } // 包含 taken = getMax(start + 2,array) + array[start]; // 取最大值 return Math.max(taken,untaken); } }
- 时间复杂度:,递归函数的计算时间复杂度为指数级;
- 空间复杂度:,递归调用栈的空间大小为n。
方法二
思路
- 动态规划;
- 方法一的时间复杂度过大,程序运行期间栈溢出;
- 方法一在递归运算中会有很多的冗余计算,譬如说在计算f(4)时,需要取计算f(3),f(2),f(1)等。
- 故可以在采用自底向上的方法,依据方法一的递推公式,记录每一个子问题的最大子序列和,从而降低时间复杂度。
- 创建一维数组dp存放计算的结果
- 依次计算f(1),f(2),f(3)……f(n)
- f(n)即为所求的不相邻最大子序列和。
- 对于数组[4,3,2,1,5,6,7]参考下图示例:
- 代码如下:
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * 计算 * @param n int整型 数组的长度 * @param array int整型一维数组 长度为n的数组 * @return long长整型 */ public long subsequence (int n, int[] array) { if (n == 0){ return 0; } // 创建一维数组,辅助计算 long[] dp = new long[n]; // 当序列长度为1时 dp[0] = Math.max(0,array[0]); if (n == 1){ return dp[0]; } // 序列长度为2时 dp[1] = Math.max(dp[1],array[1]); // 遍历 for(int i = 2;i < n;++i){ dp[i] = Math.max(dp[i-1],dp[i-2] + array[i]); } return dp[n-1]; } }
- 时间复杂度:,一层循环;
- 空间复杂度:,一维数组;
方法三
思路
- 动态规划
- 方法二的空间复杂度为,可以考虑将其降低为;
- 在计算f(n)中实际上用到的也就是f(n-1)和f(n-2),所以只需设置两个变量b(f(n-1)),a(f(n-2)),在每一轮计算过后更新a=b,b=f(n)即可。
- 代码如下:
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * 计算 * @param n int整型 数组的长度 * @param array int整型一维数组 长度为n的数组 * @return long长整型 */ public long subsequence (int n, int[] array) { if (n == 0){ return 0; } // 当序列长度为1时 long a = Math.max(0,array[0]); if (n == 1){ return a; } // 序列长度为2时 long b = Math.max(a,array[1]); // 遍历 for(int i = 2;i < n;++i){ long temp = b; b = Math.max(b,a + array[i]); a = temp; } return b; } }
- 时间复杂度:,一重循环;
- 空间复杂度:,常数级空间复杂度。