Topic 1:添加逗号
像这种题就是应该简单题简单做,刚拿题目我还在考虑用rbegin() rend()来倒着遍历,鼓捣了半天结果insert()不能搭配反向迭代器使用,只能搭配正向迭代器,还不如直接用数组
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
cin >> str;
size_t len = str.length();
for(int i = len - 3; i > 0; i -= 3)
{
str.insert(i, ",");
}
cout << str << endl;
return 0;
}
Topic 2:跳台阶
也是一个经典中的经典,跳台阶 | 爬楼梯 | 最小花费爬楼梯,动态规划+斐波那契的问题,需要反复复习
首先还是先确定dp数组的含义 dp[n] —— 达到第 n 阶台阶,有dp[n]种方式
然后确定递推公式,每次只能走1 or 2 步长,那么达到dp[n]就可以由dp[n - 1]和dp[n - 2]推出 ,也只和这前两阶有关,可以画个图看看
由于步长的关系(1or2步),每一阶的关系也只和前两阶有关,从1阶开始,1阶之前只有地面,所以只有1种方式到1阶,走1步(绿色);
2阶可以从1阶上,也能从地面上(红色),所以是1(到1阶有1种方式)+ 1 = 2种;
3阶则是能从1阶和2阶到达(蓝色),也就是1(到1阶有1种方式)+ 2 (到2阶有2种方式)= 3种;
同理,4阶(紫色)就是(到2阶有2种方式)+(到3阶有3种方式) = 5种
5阶(橙色)就是(到3阶有3种方式)+(到4阶有5种方式) = 8种,依此类推
所以公式就是dp[n] = dp[n - 1] + dp[n - 2],接下就可以做初始化了,那么dp[0]应该初始化为多少?才方便往上推呢?根据 dp[n] —— 达到第 n 阶台阶,有dp[n]种方式 的含义,应该是dp[1] = 1, dp[2] = 2, 比较合理
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param number int整型
* @return int整型
*/
int jumpFloor(int number)
{
// dp[n] = dp[n - 1] + dp[n - 2]
if (number <= 1) return 1; // 1阶台阶,只有1种方式
vector<int> dp(number + 1);
dp[0] = 1;// 实际上是没有意义的,只是为了防止边界溢出
dp[1] = 1;
dp[2] = 2;
for(int i = 2; i <= number; ++i)
{
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp.back();
}
};
更直观,其实就是斐波那契的写法了
class Solution {
public:
int jumpFloor(int number) {
if (number <= 1) return 1;// 输入如果是0阶 1阶返回1 对应斐波那契
int a = 1, b = 1, c;// a 0阶 b 1阶
for (int i = 2; i <= number; ++i) // 从2阶开始算
{
c = a + b;// 2阶 = 0阶 + 1阶
a = b;// 0阶变1阶
b = c;// 1阶变2阶
//循环往复,直至最后到要求的number数
}
return b;// 输出这一阶的方法数
}
};
其实这个题目还有个比较有意思的衍生可以推一推,就是当每次不止走1or2步,要是每次最多能走m步,怎么推呢?
基础动态规划
int jumpFloorM(int n, int m) {
if (n <= 1) return 1;
vector<int> dp(n + 1, 0);
dp[0] = 1; // 初始条件
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m && j <= i; ++j) {
dp[i] += dp[i - j];
}
}
return dp[n];
}
滑动窗口优化,先码住,之后有时间再回来分析
int jumpFloorM(int n, int m) {
if (n <= 1) return 1;
vector<int> dp(n + 1, 0);
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= n; ++i) {
if (i <= m) {
// 前 i 项和(dp[0]到dp[i-1])
dp[i] = 2 * dp[i - 1];
} else {
// 滑动窗口:dp[i] = dp[i-1] * 2 - dp[i - m - 1]
dp[i] = 2 * dp[i - 1] - dp[i - m - 1];
}
}
return dp[n];
}
Topic 3:扑克牌顺子
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param numbers int整型vector
* @return bool布尔型
*/
bool IsContinuous(vector<int>& numbers)
{
//规律
//1 不能有重复非零数字
//2 最大数-最小数不能超过5,每个数字连续的话差值就是1嘛,1 2 3 4 5 5-1 = 4 5 6 7 8 9 9-5 = 4
//3 数组长度为5,很多人觉得反证不好证明就是因为忘了这个条件,当然题目已经规定了只有五张牌
//本题中,有两个非零数满足1、2两个条件就可以判定为顺子了,这就是确认极值来划定范围的思路
sort(numbers.begin(), numbers.end());// nlogn就是因为这个sort,用哈希可以到N
int zero = 0;// 计数0
for (int i = 0; i < 4; ++i)
{
if (numbers[i] == 0) ++zero;
if (numbers[i] != 0 && numbers[i + 1] != 0 && numbers[i] == numbers[i + 1]) return false;
}
if(numbers[4] - numbers[zero] < 5) return true;
return false;
}
};
思路理好了代码可以写的很简单