C++日常刷题积累
- 今日刷题汇总 - day004
- 1、Fibonacci数列
- 1.1、题目
- 1.2、思路
- 1.3、程序实现
- 2、单词搜索
- 2.1、题目
- 2.2、思路
- 2.3、程序实现
- 3、杨辉三角
- 3.1、题目
- 3.2、思路
- 3.3、程序实现 - 蛮力法
- 3.4、程序实现 - vector
- 3.5、程序实现 - dp
- 4、题目链接
今日刷题汇总 - day004
1、Fibonacci数列
1.1、题目
1.2、思路
首先,读完题知道了要求,对输入的数值N操作++或–,使其变成一个斐波那契数的操作次数最小。那么斐波那契数众所周知相邻数之间具备一定的关系,即第三个数c = 第一个数a + 第二个数b;那么,我们输入的数值N肯定是在b和c之间或者正好是斐波那契数(可能不好理解,补充几句,斐波那契数列的规律是abc,abc,abc的迭代的,所以最先接触到输入值N的是c,所以肯定在b和c之间,而不会在a和b之间),故由最近的b和c与输入的数值N求的最小差就是最小操作的次数。接下来,就是程序实现。
1.3、程序实现
首先,按照题目要写好输入,以及定义斐波那契数的三个相邻数且从 0,1,1开始循环斐波那契数,直到把输入值n包括进b和c之间。最后求得最小差值即可。
#include <iostream>
using namespace std;
int main()
{
int n = 0;
cin >> n;
int a = 0;
int b = 1;
int c = 1;
while(n > c)
{
a= b;
b = c;
c = a+b;
}
cout << min(c - n, n - b) << endl;
return 0;
}
2、单词搜索
2.1、题目
2.2、思路
首先,读完题目,知道了在一个二维字符数组中,进行查找相邻的元素组成需要的单词。其中,要求同一个字符元素只能用一次,即单向的拼接。那么,分析示例,可以想到遍历二维数组,当出现第一个与输入的单词首字母匹配时。执行查找相邻的字符元素执行拼接,如果这次拼接未完成,则继续遍历第二次出现,输入单词的首字母,再次执行查找拼接。遍历结束后,还是没有拼接成功,说明这组二维数组没有该单词。读懂了题,那么怎么来解决呢?思考后,这道题实际上考察的是深度优先搜索的方法。首先,我们先得知道二维数组vis得大小m行,n列,然后vis初始化为0表示未被搜索过,接着需要两个方向数组dx和dy,然后就可以遍历这个二维数组,当遍历到等于单词首字母word[0]时,执行深度优先搜索dfs,dfs查找匹配拼接成功就返回true,否则返回false,那么就继续遍历,依次类推,直到遍历结束。所以,我们还需要单独封装dfs函数。那么对于,dfs我们需要的参数是,这个二维数组board、当前遍历到的下标 i 和 j ,需要匹配拼接的单词,其次,还有已匹配至的位置pos,因为可能单词匹配一半就失败了,所以需要一个pos作为参数控制查找的边界。接下来具体,看看程序实现。
2.3、程序实现
首先,根据题目写好基本需求,定义bool类型的vis二维数组用于表示是否已经搜索,定义两个变量m,n计算输入二位字符数组的行、列,再定义dfs需要的方向数组dx,dy,然后写好两层for遍历匹配word[0]的程序,匹配就当前元素位置执行dfs搜索,如果遍历完都不匹配word[0],说明没有该单词。另外,值得注意的是,因为dfs也需要使用这些变量,所以定义为全局的更适用。
class Solution {
int m,n;
bool vis[101][101] = { 0 };
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
public:
bool exist(vector<string>& board, string word)
{
m = board.size();
n = board[0].size();
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (board[i][j] == word[0])
{
if(dfs(board, i, j, word, 0))
return true;
}
}
}
return false;
}
};
接着,就是根据题目规则,编写dfs函数,首先,能进入dfs执行查找,说明当前位置的字符元素下标 i 和 j 与word[0]是匹配的,所以vis[i][j] = true,标记被搜索了,接着我们去按照规则去当前标记处的上下左右4个方向去搜索匹配word[1]第二个字母,值得注意的是,我们需要约束查找的边界,比如当在vis[0][0]就匹配word[0]时,执行dfs如果四个方向都去查找的时候,发现,vis[0][0]的上方和左方不存在,所以类似的边界需要利用两个变量a和b控制,并且我们要保证下一次不会再次搜索同一位置!vis[a][b],而是去匹配word[pos + 1]单词的下一个位置字母。如果第二个字母也成功匹配了,继续递归dfs找匹配第三个字母,依次类推,直到查看当前pos是否是word的最后一个位置,如果是说明查找成功,拼接成功返回true,否则,不存在该单词或查找失败,返回false。值得注意的是,遍历结束后无法匹配,需要把vis[i][j] 置false表示取消标记,方便下次标记的使用.
class Solution {
int m,n;
bool vis[101][101] = { 0 };
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
public:
bool dfs(vector<string>& board, int i, int j, string& word, int pos)
{
vis[i][j] = true;
for (int k = 0; k < 4; k++)
{
int a = i + dx[k], b = j + dy[k];
if (a >= 0 && a < m && b >= 0 && b < n && !vis[a][b] && board[a][b]== word[pos + 1])
{
if (dfs(board, a, b, word, pos + 1))
return true;
}
}
if (pos == word.size() - 1)
{
return true;
}
vis[i][j] = false;
return false;
}
bool exist(vector<string>& board, string word)
{
m = board.size();
n = board[0].size();
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (board[i][j] == word[0])
{
if(dfs(board, i, j, word, 0))
return true;
}
}
}
return false;
}
};
3、杨辉三角
3.1、题目
3.2、思路
读完题目,知道就是熟悉的杨辉三角,输入n表示输出几行的杨辉三角即可。杨辉三角的特点就是边界上全为1,且除第1,2层和边界元素外的元素 = 上层元素 + 上层元素前一个元素,即arr[i][j] = arr[i-1][j] + arr[i-] [j-1];那么比较简单那么就用三种方法实现,蛮力法、vector法以及dp法。说说后面两种思路即可。vector就是利用vector套一层vector组成二维数组,且方便利用resize初始化为1,然后结合杨辉三角的性质逐个相加即可,最好按照题目要求输出即可;dp线性问题,就巧妙了,直接把足够大二维数组初始化为0,然后从arr[1][1]开始填入杨辉三角,第几行就打印几列即可。接下来就是程序实现。
3.3、程序实现 - 蛮力法
首先,按照题目要求,写好输入n表示行,然后,定义一个二维数组arr符合题目范围即可,然后杨辉三角经典的两层for先写上,这里定义全局的 i 和 j 因为后续的打印也是两层遍历二维数组打印,所以全局更适用。值得注意的是,打印按照题目要求的格式5d打印一行且换行。
#include <iostream>
using namespace std;
int main()
{
int n = 0;
cin >> n;
int arr[31][31];
int i;int j;
for (i = 0; i < n; i++)
{
for (j = 0; j <= i; j++)
{
}
}
for (i = 0; i < n; i++)
{
for (j = 0; j <=i; j++)
printf("%5d", arr[i][j]);
printf("\n");
}
return 0;
}
接着,完善杨辉三角的性质,初始化第一列j = 0 和 i == j边界(斜边)等于1,套上“公式”arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];即可。
#include <iostream>
using namespace std;
int main()
{
int n = 0;
cin >> n;
int arr[31][31];
int i;int j;
for (i = 0; i < n; i++)
{
for (j = 0; j <= i; j++)
{
if (j == 0 || i == j)
{
arr[i][j] = 1;
}
else
{
arr[i][j] = arr[i - 1][j - 1] + arr[i - 1][j];
}
}
}
for (i = 0; i < n; i++)
{
for (j = 0; j <=i; j++)
printf("%5d", arr[i][j]);
printf("\n");
}
return 0;
}
3.4、程序实现 - vector
整体思路都差不多,vector主要是用一下vector的应用,主要可以概括为三步:
(1)、利用resize初始化二维数组vector<vector> vv(n);全是为1;
(2)、根据杨辉三角性质写好两层for循环;值得注意的是循环边界控制,从i=2第三行开始即可。
(3)、根据题目要求的格式打印即可。
#include <iostream>
#include <vector>
using namespace std;
int main()
{
int n = 0;
cin >> n;
vector<vector<int>> vv(n);
for (int i = 0; i < n; i++)
{
vv[i].resize(i + 1, 1);
}
for (int i = 2; i < n; i++)
{
for (int j = 1; j < i; ++j)
{
vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
}
}
for(int i = 0; i < n; i++)
{
for(int j = 0; j <= i; j++)
{
printf("%5d", vv[i][j]);
}
printf("\n");
}
return 0;
}
3.5、程序实现 - dp
线性dp就是利用把杨辉三角从arr[1][1]开始填入数据1,而不是从arr[0][0],因为这样就不用遍历使得边界初始化为1了。直接就可以集合杨辉三角的性质dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];得到每一个数据。前提是数组满足题目范围足够大。为了方便理解画个图,以n=4为例观察。
此外,这里直接定义全局的数组dp,因为全局默认初始化为全0。值得注意的是dp优化后,打印二维数组从1开始。
#include <iostream>
using namespace std;
int dp[31][31];
int main()
{
int n = 0;
cin >> n;
dp[1][1] = 1;
for(int i = 2; i <= n; i++)
{
for(int j = 1; j <= i; j++)
{
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
}
}
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= i; j++)
{
printf("%5d", dp[i][j]);
}
printf("\n");
}
return 0;
}
4、题目链接
Fibonacci数列
单词搜索
杨辉三角