文章目录
Tips:注意文章中标红的地方,这些都是容易犯错的地方
leecode面试题16.11——跳水板
- 题目描述:
面试题 16.11. 跳水板
你正在使用一堆木板建造跳水板。有两种类型的木板,其中长度较短的木板长度为shorter,长度较长的木板长度为longer。你必须正好使用k块木板。编写一个方法,生成跳水板所有可能的长度。
返回的长度需要从小到大排列。
示例 1
输入:
shorter = 1
longer = 2
k = 3
输出: [3,4,5,6]
解释:
可以使用 3 次 shorter,得到结果 3;使用 2 次 shorter 和 1 次 longer,得到结果 4 。以此类推,得到最终结果。
提示:
0 < shorter <= longer
0 <= k <= 100000
- 分析:
咋说呢,分类是分到了递归的这里,但并不觉得递归是个解决本题的最佳方法。
本题就直接用r[i] = shorter*i + longer*(k-i)
来实现就行。
- 注意1: 处理两个特殊情况:k值小于等于0、shorter值等于longer的情况。
k小于等于0这个特殊情况很容易想到,但shorter=longer的情况是真的没想到,测试用例没通过才想到这种情况,当两个值相等时,这个时候输出数组就一个值就是shorter*k,要是还是按照通用方法,最后会输出k个一样的值。如图所示:
- 注意2: 根据所给的输出示例,给出题目要求的输出,本题的要求就是shorter这个值的个数从大到小去计算。
比如说这个测试用例,我得到的值是对着,但答案的顺序和要求的有出入,因此观察所给的输入输出示例则能得到要求的值。
- 代码:
class Solution {
public:
vector<int> divingBoard(int shorter, int longer, int k)
{
vector<int> r;
if(k<=0)
return r;
if(shorter == longer)
{
r.push_back(shorter*k);
return r;
}
for(int i=k;i>=0;i--)
{
r.push_back(shorter*i + longer*(k-i));
}
return r;
}
};
leecode1137——第N个泰波那契数
- 题目描述:
- 第 N 个泰波那契数
泰波那契序列 Tn 定义如下:
T0 = 0, T1 = 1, T2 = 1, 且在 n >= 0 的条件下 Tn+3 = Tn + Tn+1 + Tn+2
给你整数 n,请返回第 n 个泰波那契数 Tn 的值。
示例 1:
输入:n = 4
输出:4
解释:
T_3 = 0 + 1 + 1 = 2
T_4 = 1 + 1 + 2 = 4
示例 2:
输入:n = 25
输出:1389537
提示:
0 <= n <= 37
答案保证是一个 32 位整数,即 answer <= 2^31 - 1。
这个名字硬生生的把tribonacci翻译成了中式英语
- 分析:
- 递归肯定是超时了,因为重复的计算太多了,所以需要用到递归的优化:考虑保存重复计算值或者考虑自下而上的递推方法。
- 这个题有意思了,刚刚复习的小青蛙跳台阶的优化方法递推方法刚好派上用场。
- 代码:
注意: 递推的方式中约束条件的n也要算上!
class Solution {
public:
int tribonacci(int n)
{
if(n < 2)
return n;
if(n == 2)
return 1;
int f0 = 0, f1 = 1, f2 = 1;
int sum123 = 0;
for(int i=3;i<=n;i++)//注意是i<=n
{
sum123 = f0 + f1 + f2;
f0 = f1;
f1 = f2;
f2 = sum123;
}
return sum123;
}
};
- 补充:python简洁方法,不看函数定义,因为定义给了,你直接写函数内容。把这个贴出来的原因是为了理解三个f1,f2,f3之间的赋值。
class Solution:
def tribonacci(self, n: int) -> int:
a, b, c = 0, 1, 1
for i in range(n) :
a, b, c = b, c, a+b+c
return a
leecode面试题 08.05. ——递归乘法
- 题目描述:
面试题 08.05. 递归乘法
递归乘法。 写一个递归函数,不使用 * 运算符, 实现两个正整数的相乘。可以使用加号、减号、位移,但要吝啬一些。
示例1:
输入:A = 1, B = 10
输出:10
示例2:
输入:A = 3, B = 4
输出:12
提示:
保证乘法范围不会溢出
- 分析:
本题依然用的是递归三要素,真的很好用 - 代码:
class Solution {
public:
int multiply(int A, int B)
{
//2. 递归结束的条件
if(A==1)
return B;
else if(B==1)
return A;
//3. 寻找函数的等价关系式
return A + multiply(A, B-1);
}
};
leecode698. ——划分为k个相等的子集
- 题目描述:
- 划分为k个相等的子集
给定一个整数数组 nums 和一个正整数 k,找出是否有可能把这个数组分成 k 个非空子集,其总和都相等。
示例 1:
输入: nums = [4, 3, 2, 3, 5, 2, 1], k = 4
输出: True
说明: 有可能将其分成 4 个子集(5),(1,4),(2,3),(2,3)等于总和。
提示:
1 <= k <= len(nums) <= 16
0 < nums[i] < 10000
- 分析:
这个题说实话挺难理解的,抄了大佬的代码,还是理解了很长时间。
这个实现用了两个函数和一个全局变量:
- 函数1实现对原数组的处理,包括计算这个要搜索的总和target=数组总和/k,将数组元素用哈希表进行保存,方便后边用dfs进行搜索,还有就是特殊情况的处理,包括target不存在的情况和数组最大值大于这个target的情况,都是返回false;
- 函数2实现dfs深度优先搜索:实现寻找k个target是否能在数组中组合存在。难理解的是核心dfs部分,用了一个for循环取遍历了所有可能的情况。
- 代码:
class Solution {
public:
int x=0;
bool canPartitionKSubsets(vector<int>& nums, int k)
{
int len = nums.size();
int sum = 0;
unordered_map<int, int> hashMap;
int maxNum = 0;
for(int i=0;i<len;i++)
{
sum += nums[i];
hashMap[nums[i]]++;
maxNum = nums[i]>maxNum? nums[i]:maxNum;
}
int target = sum/k;
x = target;
if(sum%k != 0 || maxNum > target)
return false;
return dfs(hashMap, k, 0);//DFS搜索x个target看是否存在
}
//DFS寻找kNew个target,newTarget是上一个子集剩余的需要寻找的元素
bool dfs(unordered_map<int, int> &hashMap, int kNew, int newTarget)
{
//DFS递归结束条件
if(newTarget == 0)
{
if(kNew == 0)
{
return true;
}
else
{
return dfs(hashMap, kNew-1, x);//当前子集搜索完毕,搜索下一个
}
}
//DFS搜索target,从数组中最大的值开始搜索
for(int i=newTarget;i>0;i--)
{
if(hashMap[i]>0)
{
hashMap[i]--;
if(dfs(hashMap, kNew, newTarget-i))//递归继续搜索target-i
return true;
hashMap[i] += 1;
}
}
return false;
}
};