数学题集合
一、907. 子数组的最小值之和
传送门
https://leetcode-cn.com/problems/sum-of-subarray-minimums/
结题思路
题目输入输出几变量包装
给定一个整数数组 A,找到 min(B) 的总和,其中 B 的范围为 A 的每个(连续)子数组。
由于答案可能很大,因此返回答案模 10^9 + 7。
示例:
输入:[3,1,2,4]
输出:17
解释:
子数组为 [3],[1],[2],[4],[3,1],[1,2],[2,4],[3,1,2],[1,2,4],[3,1,2,4]。
最小值为 3,1,2,4,1,1,2,1,1,1,和为 17。
特殊值的思考方法
算法步骤
思路1:使用单调栈的思想,实现一个单调栈:新建一个map,map的key为数组的值,map的value为遍历到i位置为止,遇到大于等于a[i]的个数;将map的value值存为一个单调栈,最后的最小值之和为单调栈的key*value的和值。
单调栈:单调栈指的是栈中存放的数据出栈应该是有序的,而不是输入数组所有打印数据都是有序的
思路2:暴力法:第一个循环遍历长度i,第二个循环遍历内部取这i个数,其实也就是用i个循环,感觉有点不太好,也不知道能不能做出来
源代码
#include <iostream>
#include <cmath>
#include <stdlib.h>
#include <vector>
#include <map>
using namespace std;
int main()
{
return 0;
}
题型分析
知识点与模板代码
二、1143. 最长公共子序列 = DP解决 + 状态转移方程 + 数据结构的初始化
传送门
https://leetcode-cn.com/problems/longest-common-subsequence/
算法步骤
思路1:子序列的问题,一般用DP可以来解决;否则,要试用的子序列太多了。
- 用一个dp数组存储,value为截止到字符串1的第i个,字符串2的第j个为止,最长的公共子序列。
- 如果找到相等的,则从左上角进行状态转移;如果不相等,则从左边或上边进行转移。
源代码
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int len1 = text1.length();
int len2 = text2.length();
int dp[len1+1][len2+1];
memset(dp, 0, sizeof(int)*(len1+1)*(len2+1));
for(int i = 1; i <= len1; i++)
{
for(int j = 1; j <= len2; j++)
{
if(text1[i-1] == text2[j-1])
{
dp[i][j] = dp[i-1][j-1] + 1;
}
else
{
dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
cout << dp[i][j] <<" ";
}
cout << endl;
}
return dp[len1][len2];
}
};
题型分析
- 可以用动态规划的方法来解决,因为子序列类型的问题,穷举出所有的结果都不容易,只要涉及子序列问题,十有八九可以用DP来解决。
- 注意状态转移方程的特点:当字符串相等时,从左上角转移;当不相等时,从左边或上边转移。
- 打印数组结果。
知识点与模板代码
int *dp;
int len1 = text1.length();
int len2 = text2.length();
memset(dp, 0, sizeof(int)*len1*len2);
for(int i = 1; i <= len1; i++)
{
for(int j = 1; j <= len2; j++)
{
if(text1[i-1] == text[j-1])
{
dp[i][j] = dp[i-1][j-1] + 1;
}
else
{
dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
}
三、322. 零钱兑换
传送门
https://leetcode-cn.com/problems/coin-change/
题型分析
- 动归问题分两种:一种可以用DP table的转移来解决;另一种可用变化目标来解决。
四、剑指 Offer 54. 二叉搜索树的第k大节点
传送门
https://leetcode-cn.com/problems/er-cha-sou-suo-shu-de-di-kda-jie-dian-lcof/
结题思路
特殊值的思考方法
算法步骤
思路1:使用前序遍历的倒序来解决。
- 判断k是否等于0,若是,返回根节点值;否则,进入2。
- dfs()传入根节点。先判断此节点是否为空,为空则直接return;否则,进入3。
- 遍历此节点的右子节点,接着判断–k是否等于,若等于0,则return root.val。
- dfs遍历左节点。
源代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int res = 0;
void dfs(TreeNode* root, int k)
{
if(root == nullptr || k == 0)
{
return;
}
dfs(root->right, k);
if(--k == 0)
{
res = root->val;
return;
}
dfs(root->left, k);
}
int kthLargest(TreeNode* root, int k) {
dfs(root, k);
return res;
}
};
题型分析
- 搜索二叉树,前序遍历的的判断。
五、算法训练 Rotatable Number
传送门
http://lx.lanqiao.cn/problem.page?gpid=T629
六、 复旦大学2020考研机试题 A.斗牛
传送门
https://blog.csdn.net/hyacinthhome/article/details/105952974/
结题思路
题目输入输出几变量包装
特殊值的思考方法
算法步骤
思路1:暴力法,使用不等于号避免选到重复的元素
- 三个for循环,遍历0-4。
- 用不等于号避免选到重复的元素。
- 判断其和是否等于10;若等于,则从数组中排除这几个元素。
思路2:逆向思维,选两个数;判断剩余的三个数是否和为10。
- 两个for循环,选两个数;判断剩余的三个数是否和为10。
源代码
思路1:
#include <iostream>
#include <cmath>
#include <stdlib.h>
using namespace std;
int b[2];
int cal(int i, int j, int k, int *a)
{
int v = 0;
cout << "111" << endl;
for(int p = 0; p < 5; p++)
{
if(i != p && p != k && p != k)
{
b[v++] = a[p];
cout << "a[p]:" << a[p] << endl;
}
}
if(v == 2)
{
return 1;
}
}
int main()
{
int n, sum;
int *a;
cin >> n;
a = (int *)calloc(0, sizeof(int)*5*n);
for(int i = 0; i < n; i++)
{
for(int j = 0; j < 5; j++)
{
cin >> a[i];
}
int ret = -1;
for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 5; j++)
{
for(int k = 0; k < 5; k++)
{
if(i != j && i != k && j != k && (a[i] + a[j] + a[k] == 10))
{
ret = cal(i, j, k, a);
}
}
}
}
if(ret == 1)
{
for(int i = 0; i < 2; i++)
{
sum += b[i];
}
}
cout << sum % 10 << endl;
}
return 0;
}
思路2:
题型分析
- 数组元素的选择题,注意使用!=号除去相同的元素。
- 思路2是逆向思维,更加方便。
- 比赛中尽量用简单的想法写,它又不看你代码,过了就行。
知识点与模板代码
七、历届试题 小数第n位
传送门
http://lx.lanqiao.cn/problem.page?gpid=T456
结题思路
题目输入输出几变量包装
特殊值的思考方法
算法步骤
思路1:直接求:行不通,因为double类型只能默认保存小数点后6位
- double类型相除,获取到小数点的索引,再往后取相应位置的字符串。
思路2:模拟除法的过程,将余数部分*10
- 取到余数,余数*10/除数为第一个小数部分,更新余数的值,for循环遍历上述过程到第n次;当余数等于a除b时,更新n=n%i。
- 再对此时的余数值除三次,并输出值。
源代码
#include <iostream>
#include <cmath>
#include <stdlib.h>
#include <string>
using namespace std;
int main()
{
int n;
int a, b, tmp;
cin >> a >> b >> n ;
tmp = a % b;
for(int i = 1; i < n; i++)
{
tmp = tmp*10%b;
if(tmp%b == a%b)
{
n %= i;
}
}
for(int i = 0; i < 3; i++)
{
cout << tmp*10/b;
tmp = tmp*10%b;
}
}
题型分析
- 模拟题。模拟除法的操作。
知识点与模板代码
八、 B.打地鼠
传送门
https://blog.csdn.net/hyacinthhome/article/details/105952974
结题思路
题目输入输出几变量包装
给定 n 个整数 a1, a2, …, an 和⼀个 d,你需要选出若⼲个整数,使得将这些整数从⼩到⼤排好序之 后,任意两个相邻的数之差都不⼩于给定的 d,问最多能选多少个数出来。
【输⼊格式】 第⼀⾏两个整数 n,d (1<=n<=105, 0<=d<=109),分别表⽰整数个数和相邻整数差的下界。 第⼆⾏ n 个整数 a1, a2, …, an (1<=ai<=10^9, 1<=i<=n),表⽰给定的 n 个整数。
【输出格式】 仅⼀⾏⼀个整数,表⽰答案。
【样例输⼊】
6 2
1 4 2 8 5 7
[1 2 4 5 7 8]
【样例输出】
3
特殊值的思考方法
算法步骤
思路1:最基本的规律:只有把最小的数选出或者将最大的数选出,选出来的数才是最多的。
- 将输入的数组排序。
- 分两种情况:第一种:首先将最小的数加入到容器中,再往后遍历,当此数与容器的最后一个数差值大于d时,将其加入到容器中。第二种,首先将最大的数加入到容器中,再往前遍历,当容器的最后一个数与此数的差值大于d时,将其加入到容器中
- 取两个容器的size的较大值。
源代码
#include <iostream>
#include <string>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
int n, d;
int *a;
vector<int> v1, v2;
cin >> n >> d;
a = (int *)calloc(n, sizeof(int));
for(int i = 0; i < n; i++)
{
cin >> a[i];
}
sort(a, a+n);
v1.push_back(a[0]);
int index1 = 0;
for(int i = 1; i < n; i++)
{
if(a[i]-v1[index1] >= d)
{
v1.push_back(a[i]);
++index1;
}
}
cout << v1.size() << endl;
// v2.push_back(a[n-1]);
// int index2 = 0;
// for(int i = n-2; i >= 0; i--)
// {
// if(v2[index2] - a[i] >= d)
// {
// v2.push_back(a[i]);
// ++index2;
// }
// }
}
题型分析
- 排序添加模拟题。最基本的规律:只有把最小的数选出或者将最大的数选出,选出来的数才是最多的。
1.vector的常见用法
- 对a中的从a.begin()(包括它)到a.end()(不包括它)的元素进行从小到大排列
sort(a.begin(),a.end()); - 对a中的从a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素为1,3,2,4,倒置后为4,2,3,1
reverse(a.begin(),a.end()); - 把a中的从a.begin()(包括它)到a.end()(不包括它)的元素复制到b中,从b.begin()+1的位置(包括它)开始复制,覆盖掉原有元素
copy(a.begin(),a.end(),b.begin()+1); - 在a中的从a.begin()(包括它)到a.end()(不包括它)的元素中查找10,若存在返回其在向量中的位置
find(a.begin(),a.end(),10);
九、C.排队打饭
传送门
https://blog.csdn.net/hyacinthhome/article/details/105952974/
结题思路
题目输入输出几变量包装
特殊值的思考方法
输入
人数
4
到 耗 等
[1 3 3]
[2 2 2]
[3 9 1]
[4 3 2]
不走的人打完饭的时间:tmp
4
1 3 3
2 2 2
3 9 1
4 3 2
输出
1 4 -1 6
算法步骤
思路1:用一个数组存储每个人走不走,默认值为-1,若不走,则初始化其值为等待的时间。
- 从第一个人开始遍历每个人的打饭时间,根据下一个人的到达+等待时间是否大于上一个人的到达+消耗时间;判断此人是否在留在这里打饭。
- 若留在这里打饭,则更新tmp值与数组。
源代码
#include <iostream>
#include <cmath>
#include <stdlib.h>
using namespace std;
int main()
{
int n;
int **a, *b;
cin >> n;
a = new int* [n];
for (int i = 0; i < n; i++)
{
a[i] = new int[3];
}
int tmp = 0;
b = (int *)calloc(n, sizeof(int));
for(int i = 0; i < n; i++)
{
for(int j = 0; j < 3; j++)
{
cin >> a[i][j];
}
}
for(int i = 0; i < n; i++)
{
for(int j = 0; j < 3; j++)
{
if(a[i][0]+a[i][2] >= tmp)
{
b[i] = tmp > a[i][0] ? tmp : a[i][0];
tmp = max(tmp, a[i][0]) + a[i][1];
}
}
}
for(int i = 0; i < n; i++)
{
cout << b[i] << endl;
}
return 0;
}
题型分析
- 模拟题。需要判断是否落在特定的时间段内。
- 为二维数组初始化,先new 一个一维的数组,再在每个一维数组中,new一个长度为3的数组。
int **a;
cin >> n;
a = new int* [n];
for (int i = 0; i < n; i++)
{
a[i] = new int[3];
}
模板
int **p = new int*[m]; //m行n列型
for (i = 0; i < m; ++i) {
p[i] = new int[n];
for (j = 0; j < n; ++j)
scanf ("%d",&p[i][j]);
}
知识点与模板代码
十、D.二叉搜索树
传送门
https://blog.csdn.net/hyacinthhome/article/details/105952974/
结题思路
题目输入输出几变量包装
特殊值的思考方法
输入
5
2 3 5 1 4
思路1:
算法步骤
源代码
题型分析
知识点与模板代码
知识点与模板代码
十一、相隔天数
传送门
https://blog.csdn.net/qq_38277212/article/details/105347119
输入日期格式:YYYYMMDD,求与20190205相隔天数。
结题思路
题目输入输出几变量包装
输入:
20190208
输出:
3
特殊值的思考方法
20180105
算法步骤
思路1:
- 先计算20190205是2019年的第几天。
- 再输入的年份还剩余多少天。
- 遍历输入年份到2019年,闰年为366,平年为365,累加起来。
- 判断输入的年份是<2019年,还是在2019初到20190205之间;还是20190205到2020之间;还是2020年之后。分四种情况进行讨论。
思路2:以00000000年作为参考年份,计算输入年份到00000000的天数;20190205到00000000的天数;相减即可。
源代码
思路2:
# 20190205是2019年第36天
b = input()
days1 = 0
days2 = 0
for i in range(2019):
if(i % 4 == 0 and i % 100 != 0):
days1 += 366
elif(i % 400 == 0):
days1 += 366
else:
days1 += 365
days1 += 36
nian = int(b[0:4])
if b[4] == '0':
yue = int(b[5])
else:
yue = int(b[4:5])
if b[6] == '0':
ri = int(b[7])
else:
ri = int(b[6:7])
dayue = [1, 3, 5, 7, 8, 10, 12]
xiaoyue = [2, 4, 6, 9, 11]
tianshuRunnian = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
tianshuPingnian = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
for i in range(nian):
if(i % 4 == 0 and i % 100 != 0):
days2 += 366
elif(i % 400 == 0):
days2 += 366
else:
days2 += 365
if yue in dayue:
for i in range(yue):
days2 += tianshuRunnian[i]
if yue in xiaoyue:
for i in range(yue-1):
days2 += tianshuPingnian[i]
days2 += ri
print(days2-days1)
题型分析
- 常规模拟题。比较妙的地方是,可以引入一个参考时间,如0年0月0日,作参考,用两个日期与此参考时间的差值作为解。
知识点与模板代码
闰年:
- 普通闰年:能被4整除不能被100整除,如1900不是。
- 世纪闰年:能被400整除。
十二、最大连续子序列
传送门
https://blog.csdn.net/qq_38277212/article/details/105347563
结题思路
题目输入输出几变量包装
输入:
6
-2 11 -4 13 -5 -2
输出:
20
特殊值的思考方法
算法步骤
- 新建一个dp数组,val为带index为止的最大连续子序列;因为要求是连续序列,所以状态转移方程为:上一个值加上a[i],与单独的a[i]的最大值。max(dp[i-1]+a[i],a[i])。
源代码
n = int(input())
a = [int(i) for i in input().split()]
dp = [0]*n
dp[0] = a[0]
res = 0
for i in range(1, n):
dp[i] = max(dp[i-1] + a[i], a[i])
print(max(dp))
题型分析
1.动态规划经典题。
知识点与模板代码
十三、有向树形态
传送门
https://blog.csdn.net/qq_38277212/article/details/105348818
结题思路
思路1:
题目输入输出几变量包装
输入:
1:1
2:3
3:5
4:12
5
[1]
输出:
5
特殊值的思考方法
算法步骤
源代码
题型分析
知识点与模板代码
十四、9位ISBN,求其校验位
传送门
https://blog.csdn.net/qq_38277212/article/details/105354167
结题思路
题目输入输出几变量包装
输入1:
2-02-033598
输出1:
2-02-033598-0
输入2:
7-309-04547
输出2:
7-309-04547-5
特殊值的思考方法
算法步骤
思路1:模拟题
1.
源代码
a = input()
b = []
sum = 0
i = 10
for i in range(len(a)):
if(isinstance(a[i], int)):
sum += a[i]*i
i = i - 1
m = sum % 11
num = 11 - m
if num >= 1 and num <= 9:
res = num
elif num == 10:
res = "X"
elif num == 11:
res = 0
# + 连接字符串;“,”用来输出连续两个变量
print(a + "-" + str(res))
题型分析
知识点与模板代码
十五、中位数
传送门
https://blog.csdn.net/qq_38277212/article/details/105353860
结题思路
题目输入输出几变量包装
输入:
5
2 1 4 3 5
输入:
3
特殊值的思考方法
算法步骤
思路1:使用sort函数进行排序,然后分奇偶数输出就好了!
源代码
n = int(input())
a = [int(i) for i in input().split()]
a.sort()
len = len(a)
if len % 2 == 0:
print((a[len/2]+a[len/2-1])/2)
else:
print(a[int((len-1)/2)])
题型分析
知识点与模板代码
十六、字符串的哈夫曼编码长度
传送门
https://blog.csdn.net/qq_38277212/article/details/105061306
结题思路
题目输入输出几变量包装
问题描述:
给定一个字符串(长度不超过100),求哈夫曼编码的最短长度
样例输入:
样例1:
输入:
abbcccdddd
输出:
19
样例2:
输入:
we will we will r u
输出:
50
特殊值的思考方法
算法步骤
源代码
题型分析
知识点与模板代码
知识点与模板代码
十七、字符串的修改
传送门
http://code.mooctest.net/#/exercise/edit/4608/2986?from=mooctest
结题思路
题目输入输出几变量包装
题目描述
依旧是字符串处理,设A和B是两个字符串。我们要用最少的字符操作次数,将字符串A转换为字符串B。这里所说的字符操作共有三种:
删除一个字符;
插入一个字符;
将一个字符改为另一个字符。 对任给的两个字符串A和B,计算出将字符串A变换为字符串B所用的最少字符操作次数。
输入描述
第一行为字符串A;第二行为字符串B;字符串A和B的长度均小于200。
输出描述
只有一个正整数,为最少字符操作次数。
测试样例
输入
sfdxbqw
gfdgw
输出
4
特殊值的思考方法
[sfdxbqw]
[gfdgw]
[abcd]
[abc]
算法步骤
思路1:首先找到两个字符串连续相等最长的那一段,再从这一段出发向目标字符串改变。
- 用一个递归函数匹配两个字符串的某一位置,分三种情况进行处理:若某一个位置相等,两个字符串的索引同时向后移;若不相等,则两个字符串的索引交替变换往后移。
- 记录连续相等的字符串的长度和其开始的索引。
- 从2中记录的索引开始变换字符串。
思路2:用一个dp二维表,其表示,匹配到字符串1的i位置与字符串2的j位置,目前匹配到的最长
源代码
题型分析
知识点与模板代码
十八、字符串的哈夫曼编码长度
传送门
https://blog.csdn.net/weixin_35093872/article/details/88055475
结题思路
题目输入输出几变量包装
问题描述:
给定一个字符串(长度不超过100),求哈夫曼编码的最短长度
样例输入:
输入1:
abbcccdddd
输出1:
19
输入2:
we will we will r u
输出2:
50
特殊值的思考方法
算法步骤
源代码
题型分析
知识点与模板代码
十九、后缀表达式求值
传送门
https://blog.csdn.net/qq_38277212/article/details/105009387
结题思路
题目输入输出几变量包装
问题描述:
给定一个后缀序列,要求求值,只有加减
样例输入:
输入:
123++4-
输出:
2
特殊值的思考方法
算法步骤
思路1:计算后缀表达式:遍历数组,遇到数字则将其入栈,遇到一个运算符则用此符计算栈的最上面两个数,计算完后将结果入栈。最后栈顶元素即是结果。
- 入栈,判断,计算即可。
源代码
#include <iostream>
#include <cmath>
#include <stdlib.h>
#include <string>
#include <vector>
#include <stack>
using namespace std;
int main()
{
string a;
stack<int> st;
cin >> a;
int len1 = a.length();
st.push(a[0]);
for(int i = 0; i < len1; i++)
{
if(isdigit(a[i]))
{
st.push(a[i]-'0');
}
else if(a[i] == '+')
{
int num1 = st.top();
st.pop();
int num2 = st.top();
st.pop();
int res = num1 + num2;
st.push(res);
}
else if(a[i] == '-')
{
int num1 = st.top();
st.pop();
int num2 = st.top();
st.pop();
int res = num2 - num1;
st.push(res);
}
}
cout << st.top() << endl;
return 0;
}
题型分析
- 模拟题:新建一个栈计算后缀表达式,使用stack计算后缀表达式时,负号和除号有被减数与减数、被除数与除数之分,所以是用第二次的栈顶元素操作第一个栈顶元素。
- 注意栈的栈顶是st.top();st.pop()的返回值为void。
知识点与模板代码
后缀表达式
下面以(a+b)c为例子进行说明:
(a+b)c的逆波兰式为ab+c,假设计算机把ab+c按从左到右的顺序压入栈中,并且按照遇到运算符就把栈顶两个元素出栈,执行运算,得到的结果再入栈的原则来进行处理,那么ab+c的执行结果如下:
1)a入栈(0位置)
2)b入栈(1位置)
3)遇到运算符“+”,将a和b出栈,执行a+b的操作,得到结果d=a+b,再将d入栈(0位置)
4)c入栈(1位置)
5)遇到运算符“”,将d和c出栈,执行d*c的操作,得到结果e,再将e入栈(0位置)
经过以上运算,计算机就可以得到(a+b)*c的运算结果e了。
逆波兰式除了可以实现上述类型的运算,它还可以派生出许多新的算法,数据结构,这就需要灵活运用了。逆波兰式只是一种序列体现形式。
栈
判断栈是否为空
//判断栈是否为空
bool StackEmpty(SqStack S)
{
if(S.top == -1)
return true; //栈为空
else
return false;
}
pop()的返回值为void
二十一、无向图的最小权值连通子图
结题思路
题目输入输出几变量包装
一个无向图,顶点为N个,其中M条边已给定,现在要从K条备选边中选出若干条,使得整个图连通,且选出的边权值和最小。
第一行的两个数据分别为N顶点个数和边M的个数;下面的M行为每条边的数据,
起始点和终点,还有每条边的权值。本数据使整个图连通的最小权值之和为6.
输入
4 4
1 2 2
1 4 1
2 3 3
3 4 4
[1, 2, 3, 4]
输出
特殊值的思考方法
算法步骤
思路1:并查集:有点复杂,不太会做。
思路2:使用Prim算法:新建两个栈,新建一个结构体表示每条边。将输入的每条边都加入到第一个栈中。Prim算法是,首先将第一个结点加入第二个栈中,然后不断地寻找与第二个栈中的节点相邻的节点,所有相邻节点与第二个栈中的节点的最小值,加入到第二个栈中,直到将所有节点都加入第二个栈。
思路3:使用Kruskal算法:首先将所有的边按权值排序,
1.
源代码
题型分析
知识点与模板代码
传送门
结题思路
题目输入输出几变量包装
特殊值的思考方法
算法步骤
源代码
题型分析
知识点与模板代码
传送门
结题思路
题目输入输出几变量包装
特殊值的思考方法
算法步骤
源代码
题型分析
知识点与模板代码
传送门
结题思路
题目输入输出几变量包装
特殊值的思考方法
待思考的问题
如:怎么判断二维数组中是正方矩阵
算法步骤
源代码
你的cout其实就是一些很好的注释,表示接下来是什么东西
题型分析
知识点与模板代码
传送门
结题思路
题目输入输出几变量包装
特殊值的思考方法
待思考的问题
如:怎么判断二维数组中是正方矩阵
算法步骤
源代码
题型分析
知识点与模板代码
传送门
结题思路
题目输入输出几变量包装
特殊值的思考方法
算法步骤
源代码
题型分析
知识点与模板代码
传送门
结题思路
题目输入输出几变量包装
特殊值的思考方法
算法步骤
源代码
题型分析
知识点与模板代码