数学 (medium)
Q1 I. 剪绳子
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m-1] 。请问 k[0]k[1]…*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
方法一:数学方法
根据数学推论(能推导出来),将n划分成差不多大小的数组分段时乘积最大。根据对方程(n / x)^x 求导可以得出 x = e 时取极值。此时我们取 e 临近的2和3分别验证,可以发现3时更大。因此尽可能多划分3就能得到最大的乘积。
对三取模有三种情况0 1 2分别讨论:
class Solution {
public:
int cuttingRope(int n) {
if(n <= 3) return n-1;
int m = n/3 ,r = n%3;
if(r == 1) return pow(3,m-1)*4;
else if(r == 2) return pow(3,m)*2;
else return pow(3,m);
}
};
更简洁的:
int cuttingRope(int n) {
return n <= 3? n - 1 : pow(3, n / 3) * 4 / (4 - n % 3);
}
方法二:动态规划:注意dp数组前三个的意义,与 n > 3 不同。
class Solution {
public:
int cuttingRope(int n)
{
if(n <= 3) return n-1;
vector<int> dp(n+1,1);
dp[1] = 1;
dp[2] = 2;
dp[3] = 3;
for(int i=4; i<=n; i++)
for(int j =2 ;j <= i/2 + 1 ; j++)
{
dp[i] = max(dp[i],dp[j]*dp[i-j]);
}
return dp[n];
}
};
Q2 和为s的连续正数序列
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
- 方法一:求和公式+遍历
class Solution {
public:
vector<vector<int>> findContinuousSequence(int target) {
vector<vector<int>> res;
for(int i = 1;i <= target/2 ; i++)
{ for(int j = i+1; ;j++)
{
if((i+j)*(j-i+1)/2 > target) break;
if((i+j)*(j-i+1)/2 == target)
{
vector<int> tmp;
for(int k=i;k<=j;k++)
tmp.push_back(k);
res.push_back(tmp);
}
}
}
return res;
}
};
-
方法二:滑动窗口(1. 本题用滑动窗口更简洁 2. 不用变量存储当前和 而直接用求和公式 代码会更简洁 )
class Solution { public: vector<vector<int>> findContinuousSequence(int target) { if(target < 3) return {}; int l = 1,r = 2; int tmp = 3; vector<vector<int>> res; if(target < 3) return res; while(r <= target/2 + 1) { if(tmp == target ) { vector<int> t; for(int i=l;i <= r;i++) t.push_back(i); res.push_back(t); r++; tmp += r; } else if(tmp<target) { while(tmp<target) { r++; tmp += r;} } else{ while(tmp > target) { tmp -= l; l++;} } } return res; } };
Q3 圆圈中最后剩下的数字
0,1,···,n-1这n个数字排成一个圆圈,从数字0开始,每次从这个圆圈里删除第m个数字(删除后从下一个数字开始计数)。求出这个圆圈里剩下的最后一个数字。
例如,0、1、2、3、4这5个数字组成一个圆圈,从数字0开始每次删除第3个数字,则删除的前4个数字依次是2、0、4、1,因此最后剩下的数字是3。
本题可以用基于 ArrayList
的模拟链表,但时间复杂度较高。
本题最优解是数学递推公式,但不容易一下子就想到。。。。
class Solution {
public:
int lastRemaining(int n, int m) {
int p=0;
for(int i=2;i<=n;i++)
{
p=(p+m)%i;
}
return p+1;
}
};