准备
博主:大大怪先森(记得关注,下次不要迷路哦)
编程环境:vs2013
文章目录
前言
算法训练第三天!!!
让我们一步一步的成为大佬!!!
心中有梦,以梦为马,志存远方,不负韶华。
提示:以下是本篇文章正文内容
一、简单的动态规划问题(dp问题)
我们在解决动态规划的问题(dp问题)就是将大问题化为小问题的一个过程!!!
小编在这里给大家提供三步走的方法
第一步:状态定义
第二步:发现递归公式
第三步:初始状态定义
这三步当中最重要的当然就是第二步了,看着简单的三步做起来看就难了。
需要我们多学多练多想。后续小编特地写一篇《二十道题带你看懂动归问题》的文章。
1.1斐波那契数列
题目描述
描述:
输入描述:
一个正整数n
输出描述:
输出一个正整数。
示例:
输入:4
返回值:3
说明:根据斐波那契数列的定义可知,
fib(1)=1,fib(2)=1,fib(3)=fib(3-1)+fib(3-2)=2,fib(4)=fib(4-1)+fib(4-2)=3,所以答案为3。
思路解析
第一种方法就是递归(较为简单)此处不再过多讲解
第二种方法:dp问题
发现规律:第三个数字永远是前两个数字的和
代码实现(递归)
class Solution {
public:
int fib(int n)
{
if(n == 1 || n == 2)
{
return 1;
}
return fib(n - 1) +fib(n - 2);
}
int Fibonacci(int n) {
return fib(n);
}
};
代码实现(非递归)
class Solution {
public:
int Fibonacci(int n) {
int first = 1;
int second = 2;
int third = target;
while(target > 2)
{
third = first + second;
first = second;
second = third;
--target;
}
return third;
}
};
1.2青蛙跳台阶
题目描述
描述:
示例:
输入:
2
返回值:
2
说明:青蛙要跳上两级台阶有两种跳法,分别是:先跳一级,再跳一级或者直接跳两级。因此答案为2
oj链接:https://www.nowcoder.com/practice/8c82a5b80378478f9484d87d1c5f12a4?
题目分析
简单的动归问题:
状态定义:f(i)跳到i阶台阶的总数
状态递归: f(i) = f(i - 1) + f(i - 2)
这里说明一下:f(i - 1)相当于最后一步是跨一步走然后到达最后的台阶
那么f(i - 2)就相当于最后一步是跨两步走到最后的台阶
初始状态:f(0) = 1(0台阶,就是起点,到达0台阶的方法有一种,就是不跳[这里可能有点奇怪,但是想想,如果方法次数为0,就说明不可能开始…]), f(1) = 1;
代码实现
此处只写递归代码,非递归代码同上
class Solution {
public:
int f(int n)
{
if(n == 0 || n == 1)
{
return 1;
}
return f(n - 1) +f(n - 2);
}
int jumpFloor(int number) {
return f(number);
}
};
1.3矩形覆盖
题目描述
描述:
我们可以用 21 的小矩形横着或者竖着去覆盖更大的矩形。请问用 n 个 21 的小矩形无重叠地覆盖一个 2*n 的大矩形,从同一个方向看总共有多少种不同的方法?
输入描述:
21的小矩形的总个数n
返回值描述
覆盖一个2n的大矩形总共有多少种不同的方法(从同一个方向看)
示例:
案例一:
输入:0
返回值:0
案例二:
输入:1
返回值:1
案例三:
输入:4
返回值:5
题目分析
状态定义:f(i)表示第i块的覆盖方法
状态方程:f(i) = f(i - 1) + f(i - 2)
f(i - 1)表示最后一块竖着覆盖,
f(i - 2)表示最后两块是横着覆盖。
初始化定义:f(0) = 0;f(1) = 1;f(2) = 2;
(注意这里的f(0)我们不需要去考虑就是零很明显没有木块没有覆盖方式和上一题有所不同需要注意一下)
代码实现
class Solution {
public:
int f(int n)
{
if(n == 0)
{
return 0;
}
if(n == 1)
{
return 1;
}
if(n == 2)
{
return 2;
}
return f(n - 1) + f(n - 2);
}
int rectCover(int number) {
return f(number);
}
};
1.4求连续子数组的最大和(重点思考)
题目描述
描述:
一个数组有 N 个元素,求连续子数组的最大和。 例如:[-1,2,1],和最大的连续子数组为[2,1],其和为 3
输入:
第一行为n个数,即每个元素,每个整数都在32位int范围内。以,分隔。
输出:
所有连续子数组中和最大的值
示例:
输入:
-1 2 1
输出:
3
题目分析
状态定义:dp[i]i之前连续子数组最大和
状态方程:max(dp[i]) = getmax(dp[i - 1] + arr[i],arr[i])
初始化化定义:dp[0] = arr[0]
代码实现
#include<iostream>
#include<vector>
using namespace std;
int getmax(int a, int b)
{
return a > b ? a : b;
}
int main()
{
int x = 0;
vector<int> v;
while(cin>>x){
v.push_back(x);
char c = getchar();
if(c=='\n')
break;
}
int sum = v[0];
int max = v[0];
for (int i = 1; i < v.size(); i++)
{
sum = getmax(sum + v[i], v[i]);
if (sum > max)
{
max = sum;
}
}
cout << max << endl;
return 0;
}
二、二进制计算
题目描述
描述:
示例:
输入:
10
返回值:
2
说明:十进制中10的32位二进制表示为0000 0000 0000 0000 0000 0000 0000 1010,其中有两个1。
oj链接:
https://www.nowcoder.com/practice/8ee967e43c2c4ec193b040ea7fbb10b8?
题目分析
第一种方法:让数字循环32次每次>>一位然后再和1进行按位&操作就可就出(较简单不做太多讲解)
第二种方法:公式: n = n & (n - 1) 每一次按公式计算就可以取出n当中的一个1依次循环即可求解(如下代码)
代码实现
class Solution {
public:
int NumberOf1(int n) {
int j = 0;
int count = 0;
while(n)
{
count++;
n &= (n -1);
}
return count;
}
};
结语
希望本篇文章能给各位带来帮助,如有不足还请指正!!!
码字不易,各位大大给个收藏点赞吧!!!