岁月,对人来说,是一样人捉摸不到的东西。然而,就是这样东西,使人更珍惜自己的时光。如果,岁月可以给每一个人愿望。我希望,岁月可以倒转。
20级青藤工作室第三次考核参考答案
第一题
题目
一、证明哥德巴赫猜想
哥德巴赫猜想:任一大于 2 的偶数都可写成两个素数之和。
请涉及一个程序,输入一个不小于 2 的 int 型的偶数 n,输出两个相加和为 n 的素数。
示例一:
输入: 20
输出: 20=13+7
示例二:
输入: 98
输出: 98=19+79
源码:
#include<stdio.h>
#include<math.h>
int isPrime(int n)
{
if (n == 1 || (n % 2 == 0 && n != 2))
return 0;
else
{
int m = sqrt(n);
for (int i = 2; i <= m; i++)
{
if (n % i == 0)
return 0;
}
}
return 1;
}
void main()
{
int n;
printf("请输入一个大于2的偶数: ");
scanf("%d", &n);
for (int i = 2; i <= n / 2; i++)
{
if (isPrime(i) && isPrime(n - i))
{
printf("%d=%d+%d", n, i, n - i);
return;
}
}
}
第二题
题目
二、输入一个长度为 n 的整型数组 arr ,输出 arr 的一个最长单调递增子序列的长度
单调递增子序列:不该变原来数组顺序,从数组中抽出来的数按原来顺序排列,是从小到大
例如:
原数组:[14, 25, 16, 14, 47, 48, 5, 14]
单调递增子序列:[14, 16, 47, 48], [25, 47, 48], [16, 47, 48], [14, 47, 48], …
输入:
第一行输入:n 的大小
第二行输入:n 个整数
输出:
该数组的最长单调递增子序列的长度
例子:
输入:8
输入:[1 ,5 ,3, 8, 10, 6, 4, 9]
输出:4
源码
/**
*
* 输入一个长度为 n 的数组 arr ,输出 arr 的一个最长单调递增子序列的长度
* 单调递增子序列:不该变原来数组顺序,从数组中抽出来的数按原来顺序排列,是从小到大
* 例如:
* 原数组:[14, 25, 16, 14, 47, 48, 5, 14]
* 单调递增子序列:[14, 16, 47, 48], [25, 47, 48], [16, 47, 48], [14, 47, 48], ...
*
* 输入:
* 第一行输入:n 的大小
* 第二行输入:n 个整数
* 输出:
* 该数组的最长单调递增子序列的长度
*
* 例子:
* 输入:
* 8
* 1 5 3 8 10 6 4 9
* 输出:
* 4
*
*/
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n = 0, maxLen = 0;
// 输入数组长度 n
scanf("%d", &n);
// 定义两个长度为 n 的 int 数组
// arr 用于储存输入的 n 个整数
int *arr = (int *)malloc(sizeof(int)*n);
// dp 用于保存以当前数为最后一位的最长单调递增子序列的长度
// dp[i] 表示在数组 arr 中以 arr[i] 为最后一位的最长单调递增子序列的长度
int *dp = (int *)malloc(sizeof(int)*n);
// 输入数字存入 arr
for (int i = 0; i < n; i++) {
scanf("%d", arr+i);
}
// 以第一个数为最后一位的最长单调递增子序列的长度为 1
// 注意:下标 0 代表第一个数
dp[0]=1;
/**
* 从第一位之后,arr[i] 的 dp[i] 的值为在 0 ~ i-1 中比自己小的数 arr[j] 的 dp[j] + 1
* 且找到的 dp[j] + 1 大于 dp[i](dp[i] 的初始值为 1)
*/
for(int i = 1; i < n; i++) {
dp[i] = 1;
for(int j = 0; j < i; j++) {
if(arr[i] > arr[j]) {
dp[i] = dp[i] > dp[j]+1 ? dp[i] : dp[j]+1;
}
}
}
// 输出数组 dp 中最大的数,就是最长单调递增子序列的长度
for(int i = 0; i < n; i++) {
if(maxLen < dp[i]) {
maxLen = dp[i];
}
}
printf("%d\n", maxLen);
return 0;
}
第二种思路
#include<stdio.h>
int longestIncreasingSubsequence(int nums[], int len) {
//直接初始化最长递增子序列长度为1
int max_len = 1;
//用于保存比较过的起始值中的最小值
int min;
for (int i = 0; i < len; i++) {
//先用cur保存本次比较的起点的值
int cur = nums[i];
//保存本次比较的递增子序列长度
int cur_len = 1;
//当某次比较的长度小于等于max_len则无需继续比较,直接返回max_len
if (len - i <= max_len)
return max_len;
//当某次比较的起点的值大于该值则可以直接跳过本次循环
//因为起点值本身大于min,而本次比较的长度还小于起点为min是比较的长度
//那么得出的结果一定不大于max_len
if (i != 0 && cur >= min)
continue;
//运行到这里说明cur<min
min = cur;
for (int j = i + 1; j < len; j++) {
if (nums[j] > cur) {
cur = nums[j];
cur_len++;
}
}
//如果本次比较得出的结果大于max_len就将结果赋值给max_len
if (cur_len > max_len)
max_len = cur_len;
}
return max_len;
}
int main() {
int nums[] = { 4,5,2,8,10,6,4,9,11 };
int len = 9;
int res = longestIncreasingSubsequence(nums, len);
printf("最长递增子序列长度为:%d", res);
return 0;
}
第三题
题目
三、现有一个 n 级台阶,一只青蛙一次只能跳一阶或者两阶或者三阶,求该青蛙跳完这 n
级阶梯共有多少种方法,即请编写一个程序,输入 n (n>0),输出方法总数。
源码
#include<stdio.h>
int jump(int n)
{
if (n <= 2)
return n;
else if (n == 3)
return 4;
else
return jump(n - 1) + jump(n - 2) + jump(n - 3);
}
int main()
{
printf("请输入台阶数(>0):");
int n;
scanf("%d", &n);
printf("总共有%d种方法\n", jump(n));
return 0;
}
第四题
题目
四、给定一个二维网格和一个单词,找出该单词是否存在于网格中。单词必须按照字母顺序,
通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。
同一个单元格内的字母不允许被重复使用。
举例:
board =
[
[‘A’,‘B’,‘C’,‘E’],
[‘S’,‘F’,‘C’,‘S’],
[‘A’,‘D’,‘E’,‘E’]
]
给定 word = “ABCCED”, 返回 true
给定 word = “SEE”, 返回 true
给定 word = “ABCB”, 返回 false
源码
//1,将该题分解为:给定坐标[i,j],在二维网格中是否能够匹配单词,在二维网格中所有匹配第一个字母的位置匹配一次单词
//2,如何在二维网格中匹配一个单词,回溯法
//回溯法匹配单词 0代表失败,1代表成功
int backTrackExist(char** board, int iRowSize, int iColSize, int iRow, int iCol, char* word, char** pBFlag, int iStep)
{
int bMatch = 0;//默认为假
int iWordLen = strlen(word);
//1,结束条件
if (iStep == iWordLen - 1)
{
return 1;
}
//2,判定下一步是否有匹配单词
pBFlag[iRow][iCol] = 1;
if ((iRow - 1 >= 0) && (pBFlag[iRow - 1][iCol] == 0) && (board[iRow - 1][iCol] == word[iStep + 1]))
{
//上匹配
bMatch = backTrackExist(board, iRowSize, iColSize, iRow - 1, iCol, word, pBFlag, iStep + 1);
if (bMatch) return bMatch;
}
if ((iCol + 1 < iColSize) && (pBFlag[iRow][iCol + 1] == 0) && (board[iRow][iCol + 1] == word[iStep + 1]))
{
//右匹配
bMatch = backTrackExist(board, iRowSize, iColSize, iRow, iCol + 1, word, pBFlag, iStep + 1);
if (bMatch) return bMatch;
}
if ((iRow + 1 < iRowSize) && (pBFlag[iRow + 1][iCol] == 0) && (board[iRow + 1][iCol] == word[iStep + 1]))
{
//下匹配
bMatch = backTrackExist(board, iRowSize, iColSize, iRow + 1, iCol, word, pBFlag, iStep + 1);
if (bMatch) return bMatch;
}
if ((iCol - 1 >= 0) && (pBFlag[iRow][iCol - 1] == 0) && (board[iRow][iCol - 1] == word[iStep + 1]))
{
//左匹配
bMatch = backTrackExist(board, iRowSize, iColSize, iRow, iCol - 1, word, pBFlag, iStep + 1);
if (bMatch) return bMatch;
}
//3,回溯处理
pBFlag[iRow][iCol] = 0;
return 0;
}
int exist(char** board, int boardSize, int* boardColSize, char* word) {
int i = 0;
int j = 0;
int k = 0;
int iRow = boardSize;
int iCol = boardColSize[0];
int bRet = 0;//默认为假
char** pBoardFlag = NULL;
if ((NULL == board) || (NULL == word)) return 0;
//1,初始化二维网格匹配标记数组
pBoardFlag = (char**)malloc(sizeof(char*) * iRow);
for (i = 0; i < iRow; i++)
{
pBoardFlag[i] = (char*)malloc(sizeof(char) * iCol);
}
//2,循环二维网格,寻找坐标,进行匹配单词
for (i = 0; i < iRow; i++)
{
for (j = 0; j < iCol; j++)
{
if (board[i][j] == word[0])
{
for (k = 0; k < iRow; k++)
{
memset(pBoardFlag[k], 0x00, sizeof(char) * iCol);
}
//3,给定坐标[i,j],匹配单词
bRet = backTrackExist(board, iRow, iCol, i, j, word, pBoardFlag, 0);
if (bRet) return bRet;
}
}
}
//4,释放空间
for (k = 0; k < iRow; k++)
{
free(pBoardFlag[k]);
}
free(pBoardFlag);
return bRet;
}