据说这次台风来势凶猛,怪不得北京的天气如此反常,连续数周阴雨绵绵,但愿台风赶快离我国而去,愿更少的众生受到更少的伤害。言归正传,刚刷了一道题感觉难度还行,下面就和大家分享一下经验吧!
题目如下:
题意分析:
给定一个正整数n,请将它至少分成两个正整数且需要满足这些正整数之和为n,同时从n的所有划分方法中找出划分后各正整数的最大乘积,并返回。
方法一(记忆化搜索法)
先通过“自顶向下”思考即递归思想,形成一颗树,如下图所示。很显然从图中可以看出,存在不少的重叠子问题,所以可以在递归中加入记忆化以减少时间复杂度。
解题代码如下:
class Solution{
private:
vector<int> memo;
int max3( int a, int b, int c ){
return max( a, max(b, c) );
}
int findintegerBreak( int n ){
if ( n == 1 ) return 1;
if ( memo[n] != -1)
return memo[n];
int res = -1;
for ( int i = 1; i < n; i++ ) {
res = max3( res, i*(n - i), i*findintegerBreak(n - i) );
}
memo[n] = res;
return res;
}
public:
int integerBreak( int n ){
if ( n == 0 ) return 0;
if ( n == 1 ) return 1;
memo = vector<int>( n+1, -1 );
return findintegerBreak( n );
}
};
提交后的结果如下:
方法二(动态规划法)
一般递归问题满足以下两个条件,那么既可以用记忆化搜索的方法解决也可以用动态规划的方法解决,不过一般先用记忆化搜索的方法(自顶向下),然后再用动态规划的方法(自底而上):① 求解原问题时,有重叠子问题,② 求解原问题时,有最优子结构,即通过求解子问题的最优解可以获得原问题的最优解。
有了方法一的基础,方法二就很容易想了,主要是维护一个数组memo,让其记录到达某个正整数时的最大乘积,以便后面的正整数在划分时直接调用,这样可以大大减小时间复杂度。
解题代码如下:
class Solution{
public:
int max3( int a, int b, int c ){
return max( a, max(b, c) );
}
int integerBreak( int n ){
vector<int> memo( n+1, -1 );
memo[1] = 1;
for (int i = 2; i <= n; i++) {
for (int j = 1; j <= i-1; ++j) {
memo[i] = max3( memo[i], j*(i-j), j*memo[i-j] );
}
}
return memo[n];
}
};
提交后的结果如下:
日积月累,与君共进,增增小结,未完待续。