2021
第一题
这个题的注意事项是计算阶乘时的方法!
#include <stdio.h>
int main(){
int n;
scanf("%d",&n);
double res = 0, factor = 1/1;
for(int i = 1; i<=n; i++){
factor /= i;
res += factor;
}
printf("%.4f",res);
return 0;
}
第二题
#include <stdio.h>
int main()
{
long long a,b,c;
scanf("%lld%lld",&a,&b); //%d,%ld,%lld 分别对应 printf 的参数类型 int,long 和 long long
c = a ^ b;
int res = 0;
for(int i = 1; i <= 64; i++)
{
if(c & 1) res++;
c >>= 1;
}
printf("%d",res);
return 0;
}
第三题
leetcode 679 24点游戏
c++版本,用于理解思路
class Solution {
public:
vector<double> next(vector<double> nums,int a,int b,char op){
double x;
if(op == '+') x = nums[a] + nums[b];
else if(op == '-') x = nums[a] - nums[b];
else if(op == '*') x = nums[a] * nums[b];
else if(op == '/') x = nums[a] / nums[b];
vector<double> res;
for(int i = 0; i < nums.size();i++){
if(i == a || i == b) continue;
res.push_back(nums[i]);
}
res.push_back(x);
return res;
}
bool dfs(vector<double> nums)
{
if(nums.size() == 1){
if(fabs(nums[0] - 24) < 1e-8) return true;
return false;
}
for(int i = 0; i < nums.size(); i++){
for(int j = 0; j < nums.size(); j++){
if(i == j) continue;
int a = i, b = j;
if(dfs(next(nums,a,b,'+'))) return true;
if(dfs(next(nums,a,b,'-'))) return true;
if(dfs(next(nums,a,b,'*'))) return true;
if(nums[b] != 0 && dfs(next(nums,a,b,'/'))) return true;
}
}
return false;
}
bool judgePoint24(vector<int>& cards) {
vector<double> nums;
for(int i = 0; i < cards.size();i++) nums.push_back(cards[i]);
return dfs(nums);
}
};
bool dfs(double* nums,int n)
{
if (n == 0) {
return false;
}
if(n == 1){
if(fabs(nums[0]-24)<1e-6) return true;
return false;
}
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
if(i == j) continue;
double a = nums[i],b = nums[j];
//这个next_nums数组必须在循环里,是因为每次枚举i j 都需要一个next_nums来存nums中除了nums[i] nums[j]的
double* next_nums = malloc(sizeof(double)*20);
int size = 0;
for(int t = 0;t<n;t++){
if(t == i || t == j) continue;
next_nums[size++] = nums[t];
}
for(int t = 0; t < 4; t++){
if(t == 0){
next_nums[size++] = a + b;
}
if(t == 1){
next_nums[size++] = a - b;
}
if(t == 2){
next_nums[size++] = a * b;
}
if(t == 3 && b != 0){
next_nums[size++] = a / b;
}
if(dfs(next_nums,size)) return true;
size--;
}
}
}
return false;
}
bool judgePoint24(int* cards, int cardsSize){
double* nums = malloc(sizeof(double)*(20));
int n = cardsSize;
for(int i = 0; i < n; i++) nums[i] = cards[i];
return dfs(nums,n);
}
此题是leetcode679 24点游戏的变形
第四题
//二进制的
#include <stdio.h>
int n;
int res[10010],pos = 0;
void change_to_binary(int n){
while(n){
res[pos] = n % 2;
n /= 2;
pos++;
}
}
int main()
{
scanf("%d",&n);
change_to_binary(n);
for(int i = pos - 1; i >= 0; i--) printf("%d",res[i]); //注意输出时是倒着输出
return 0;
}
#include <stdio.h>
int n;
int res[10010],pos = 0;
void change_to_seven(int n){
while(n){
res[pos] = n % 7;
n /= 7;
pos++;
}
}
int main()
{
scanf("%d",&n);
change_to_seven(n);
for(int i = pos - 1; i >= 0; i--) printf("%d",res[i]); //注意输出时是倒着输出
return 0;
}
2020
第一题
#include <stdio.h>
int get_num(int a,int b)
{
while(a != b){
if(a > b) a -= b;
else if(a < b) b -= a;
}
return a;
}
int main()
{
int n;
scanf("%d",&n);
while(n--){
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",get_num(a,b));
}
return 0;
}
第二题
这里考虑不qsort找到值的做法,可以考虑堆排序,输出第k次重建堆的堆首元素即可
堆排序例题
#include <stdio.h>
#define N (int)(1e6 + 10)
int h[N],n,m,cnt;
void swap(int *a,int *b)
{
int t = *b;
*b = *a;
*a = t;
}
void down(int u)
{
int t = u;
if(2*u<=cnt && h[t] > h[2*u]) t = 2*u;
if((2*u+1)<=cnt && h[t] > h[2*u+1]) t = 2*u+1;
if(t != u){
swap(&h[t],&h[u]);
down(t);
}
}
int main()
{
scanf("%d%d",&n,&m);
cnt = n;
for(int i = 1; i <= n; i++) scanf("%d",&h[i]);
for(int i = n/2;i;i--) down(i);
for(int i = 1; i <= m; i++){
printf("%d ",h[1]);
swap(&h[cnt],&h[1]);
cnt--;
down(1);
}
return 0;
}
第三题
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char** str;
int n;
char res[10000];
int cnt = 0;
int visit[100];
void dfs(char** str,int u,char res[],int cnt)
{
if(u == n){
printf("%s\n",res);
return;
}
for(int i = 0; i < n; i++){
if(visit[i]) continue;
int k = cnt; //记录原先的现场
visit[i] = 1;
int len = strlen(str[i]);
for(int j = 0; j < len; j++) res[cnt++] = str[i][j];
dfs(str,u+1,res,cnt);
cnt = k;
visit[i] = 0;
}
}
void print_res(char res[])
{
printf("%s",res);
}
int main()
{
scanf("%d",&n);
memset(res,0,sizeof(res));
str = malloc(sizeof(char*)*(110));
for(int i = 0; i < n; i++){
str[i] = malloc(sizeof(char)*110);
memset(str[i],0,sizeof(str[i]));
scanf("%s",str[i]);
}
//for(int i = 0; i < n; i++) printf("%s\n",str[i]);
dfs(str,0,res,cnt);
return 0;
}
2019
第一题
#include <stdio.h>
int weight[17] = {7,9,10,5,8,4,2,1,6,3,7,9,10,5,8,4,2};
char str[20];
int main()
{
memset(str,0,sizeof(str));
scanf("%s",str);
int res = 0;
for(int i = 0; i < 17; i++) res += (str[i] - '0')*weight[i];
res %= 11;
if(res == 10){
if(str[17] == 'X') printf("Yes\n");
else{
printf("No\n");
}
}
else{
if(res == (str[17] - '0')) printf("Yes\n");
else printf("No\n");
}
return 0;
}
第二题
判断这个十进制数字对应的二进制数字是否有两个即可
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int n;
scanf("%d",&n);
int nums[100];
memset(nums,0,sizeof(nums));
int res = 0, cnt = 0;
for(int i = 0; i < 32; i++){
if(n & 1){
res++;
nums[cnt++] = i;
}
n >>= 1; //这个别放到if里了!
}
if(res != 2) printf("No\n");
else{
printf("2^%d + 2^%d",nums[0],nums[1]);
}
return 0;
}
第三题(前缀表达式求值)
相似例题:后缀表达式求值(中缀转后缀+后缀表达式求值)
中缀形式转后缀形式:
1.数字直接保存进后缀表达式
2.操作符需要判断
(1)栈空则入栈;
(2)栈非空则比较当前op和栈顶op的优先级
当前 ‘(’ 大于所有栈顶op;
当前 ‘)’ 等于 栈顶 '(' ,小于其它栈顶op;
当前op与栈顶op同级时,当前op小于栈顶op;
当前op是 + - 小于 栈顶*/
当前op是 * / 大于 栈顶+-
(3)判断结果做处理
大于:当前op入栈
等于:此时为左右括号相遇,将栈顶op弹出且当前op不作处理
小于:栈顶op出栈并且存入后缀表达式,当前op继续与新的栈顶op比较。
3.扫描完成后若栈非空则依次出栈存入后缀表达式
后缀表达式求值
1.遍历后缀表达式
2.遇见数字时入栈
3.遇见操作符时依次出栈操作数b,a做运算a op b,结果入栈
4.遍历完成后栈内的那个元素即是结果
//这个是只能处理运算数为1位时的情况,可以先中缀转后缀再计算
//如果是 100 + 100 这种形式的运算
//就要在转后缀的过程中,运算得到结果,否则后缀会很麻烦
int priority(char op){
if(op == '*' || op == '/') return 2;
return 1;
}
int solve(char* s ) {
char* postfix = malloc(sizeof(char)*100);
int cnt = 0;
char* stack = malloc(sizeof(char)*100);
int tt = 0;
//先进行中缀转后缀表达式
for(int i = 0; i < strlen(s);i++){
if(s[i]>='0' && s[i]<='9'){ //数字直接进后缀
postfix[cnt++] = s[i];
}
else{//s[i]是个非运算符
if(s[i] == '(') stack[tt++] = s[i]; // ( 直接入符号栈
else if(s[i] == ')'){ //如果当前是)把stack中一直到 ( 中的全部弹出
while(tt && stack[tt-1] != '('){
postfix[cnt++] = stack[tt-1];
tt--;
}
tt--; //弹出 (
}
else{//s[i]为+ - * /运算符
//while(符号栈不为空 且 栈顶不为( 且栈顶符号优先级<=当前s[i]符号的优先级) 那么栈顶符号一直弹出
//最后while结束后栈顶压入s[i]
while(tt && stack[tt-1] != '(' && priority(stack[tt-1])>=priority(s[i])){
postfix[cnt++] = stack[tt-1];
tt--;
}
stack[tt++] = s[i];
}
}
}
while(tt){
postfix[cnt++] = stack[tt-1];
tt--;
}
postfix[cnt] = '\0';
printf("postfix = %s and cnt = %d \n",postfix,cnt); //到此为止完成了中缀转后缀
// 下面进行后缀表达式的计算,用到一个数字栈
int* nums = malloc(sizeof(int)*100);
int pos = 0;
for(int i = 0; i < cnt; i++){
if(postfix[i]>='0' && postfix[i]<='9') nums[pos++] = postfix[i] - '0';
else{
int a = nums[pos-2],b = nums[pos-1];
int x;
pos--,pos--;
if(postfix[i] == '+') x = a + b;
else if(postfix[i] == '-') x = a - b;
else if(postfix[i] == '*') x = a * b;
nums[pos++] = x;
}
}
return nums[0];
}
int priority(char op){
if(op == '*' || op == '/') return 2;
return 1;
}
int solve(char* s ) {
char** postfix = malloc(sizeof(char*)*100);
int cnt = 0;
for(int i = 0; i < 100; i++){
postfix[i] = malloc(sizeof(char)*1000);
memset(postfix[i],0,sizeof(postfix));
}
char* stack = malloc(sizeof(char)*1000);
int tt = 0;
int i = 0;
while(i < strlen(s))
{
if(s[i]>='0' && s[i]<='9'){
int ans = 0;
while(i < strlen(s) && s[i]>='0' && s[i] <= '9')
{
postfix[cnt][ans++] = s[i++];
}
postfix[cnt][ans] = '\0';
cnt++;
}
else{
if(s[i] == '('){
stack[tt++] = s[i++];
}
else if(s[i] == ')'){
while(tt && stack[tt-1]!='('){
postfix[cnt++][0] = stack[tt-1];
tt--;
}
tt--,i++;
}
else{
while(tt && stack[tt-1]!='(' && priority(stack[tt-1])>=priority(s[i])){
postfix[cnt++][0] = stack[tt-1];
tt--;
}
stack[tt++] = s[i];
i++;
}
}
}
while(tt){
postfix[cnt++][0] = stack[tt-1];
tt--;
}
for(int i = 0;i < cnt; i++) printf("%s",postfix[i]);
int* nums = malloc(sizeof(int)*1000);
int pos = 0;
for(i = 0; i < cnt; i++){
//printf("\ni=%d postfix[i][0]=%c ",i,postfix[i][0]);
if(postfix[i][0]>='0' && postfix[i][0] <= '9'){
int len = strlen(postfix[i]);
int tmp = 0;
for(int j = 0; j < len; j++) tmp = tmp*10 + postfix[i][j] - '0';
nums[pos++] = tmp;
//printf("%d ",tmp);
}
else{
int a = nums[pos-2],b = nums[pos-1];
pos--,pos--;
int x;
if(postfix[i][0] == '+') x = a + b;
else if(postfix[i][0] == '-') x = a - b;
else if(postfix[i][0] == '*') x = a * b;
nums[pos++] = x;
}
}
return nums[0];
}
第四题
这是一个对于 1 2 3 4 这种数字返回其集合的解答
#include <stdio.h>
#include <stdlib.h>
int n,nums[20],visit[20];
void dfs(int* nums,int u) //u代表当前遍历到了nums中的第几个位置
{
if(u == n){//u == n 代表数组中所有元素都被遍历过了,都经历过了选这个数到集合,或不选这个数到集合
for(int i = 0; i < n; i++){
if(visit[i]) printf("%d ",nums[i]);
}
printf("\n");
return;
}
visit[u] = 1; //选这个数
dfs(nums,u+1);
visit[u] = 0; //不选这个数
dfs(nums,u+1);
}
int main()
{
scanf("%d",&n);
for(int i = 0; i < n; i++) scanf("%d",&nums[i]);
memset(visit,0,sizeof(visit));
dfs(nums,0);
return 0;
}
子集的和
求划分方案数:使用DP,并且可以证明 如果 nums[i]这个数存在于一个方案中,另一个方案中就不会有nums[i]这个数,最后求出f[i][j]后 结果为 f[i][j]/2 因为两个结合能拼成一个方案
#include <stdio.h>
int n;
long long f[10010][10010];
int main()
{
scanf("%d",&n);
int m = n * (n+1)/2;
if(m % 2 == 1){
printf("0\n");
}
else{
m = m/2;
for(int i = 0; i<= n; i++) f[i][0] = 1; //前i个物品组合值为0的方案数只有1个
for(int i = 1; i <= n; i++){
for(int j = 0; j <= m; j++){
f[i][j] = f[i-1][j];
if(j>=i) f[i][j] += f[i-1][j-i];
}
}
printf("%d",f[n][m]/2);
}
return 0;
}
第五题
思路:
- 层序遍历求BST
- 树的直径(即从一个叶节点到另一个叶子节点的最大路径长度)
【hihocoder】1938.还原BST(层序遍历+BST)
这题可以这样做:对于一个层序遍历得到的序列,取序列中的第一个结点,将它后面的结点(层序遍历排在它后面的结点)分成两部分:比它小的(其左子树) 和 比它大的(其右子树)。其中,左子树中第一个结点就是它的左孩子,右子树中的第一个结点就是它的右孩子,这样就可以确定这两个结点的父节点了。接着,再分别对其右子树和左子树重复进行上述操作。
#include <stdio.h>
#include <stdlib.h>
#define N 1010
int n;
int q[N],parent[N];
void dfs(int q[],int cnt)
{
if(cnt < 0) return;
int root = q[0];
int left[N],cnt1 = -1;
int right[N],cnt2 = -1;
for(int i = 1; i <= cnt; i++){
int k = q[i];
if(root > k) left[++cnt1] = q[i];
else right[++cnt2] = q[i];
}
if(cnt1 != -1){
parent[left[0]] = root;
dfs(left,cnt1);
}
if(cnt2 != -1) {
parent[right[0]] = root;
dfs(right,cnt2);
}
}
int main()
{
scanf("%d",&n);
for(int i = 0; i < n; i++) scanf("%d",&q[i]);
parent[q[0]] = 0; //根节点没有父节点
dfs(q,n-1);
for(int i = 0; i < n; i++) printf("%d ",parent[q[i]]);
return 0;
}
Leetcode1245树的直径
int not_leaf[100010];
int visit[10010];
int g[3000][3000];
int n;
int dfs(int u,int start){
if(not_leaf[u] == 0 && start != u){ //答案要的是到叶节点的路径长度,所以本身是叶节点的路径就是0
return 0;
}
visit[u] = 1;
int res = 0;
for(int i = 0; i < n; i++){
if(g[u][i] && !visit[i]){
res = fmax(res,dfs(i,start));
}
}
return res+1;
}
int treeDiameter(int** edges, int edgesSize, int* edgesColSize){
n = 0;
memset(not_leaf,0,sizeof(not_leaf));
memset(visit,0,sizeof(visit));
memset(g,0,sizeof(g));
for(int i = 0; i < edgesSize; i++){
g[edges[i][0]][edges[i][1]] = 1;
g[edges[i][1]][edges[i][0]] = 1;
for(int j = 0; j < *edgesColSize; j++){
if(!visit[edges[i][j]]){
visit[edges[i][j]] = 1;
n++;
}
else{
not_leaf[edges[i][j]] = 1;
}
}
}
int res = -1;
for(int i = 0; i < n; i++){
memset(visit,0,sizeof(visit));
if(not_leaf[i]) continue;
res = fmax(res,dfs(i,i));
}
return res;
}
2018年
第一题
第二题
#include<stdio.h>
#include <stdlib.h>
#define N 100
int n;
struct Student{
char name[100];
char start[100];
char end[100];
int val;
}stu[N];
int cmp(const void *a,const void *b){
struct Student* aa = (struct Student*)a;
struct Student* bb = (struct Student*)b;
if(aa->val < bb->val) return 1;
return -1;
}
int main()
{
scanf("%d",&n);
for(int i = 0; i < n; i++){
scanf("%s %s %s",stu[i].name,stu[i].start,stu[i].end);
int a = (stu[i].start[0]-'0')*1000 + (stu[i].start[1]-'0')*100+(stu[i].start[3]-'0')*10+stu[i].start[4]-'0';
int b = (stu[i].end[0]-'0')*1000 + (stu[i].end[1]-'0')*100+(stu[i].end[3]-'0')*10+stu[i].end[4]-'0';
if(a < b) stu[i].val = b - a;
else stu[i].val = 100000 + a - b;
}
qsort(stu,n,sizeof(stu[0]),cmp);
printf("%s",stu[0].name);
return 0;
}
第三题
#include <stdio.h>
#include <stdlib.h>
int n,m;
int f[1010][1010];
int nums[1010];
int main()
{
scanf("%d%d",&m,&n);
for(int i = 1; i <= n; i++) scanf("%d",&nums[i]);
memset(f,0x3f,sizeof(f)); //求最小值要初始化一个较大的方案数
for(int i = 0; i <= n; i++) f[i][0] = 0;
for(int i = 1; i <= n; i++){
for(int j = 0; j <= m; j++){
f[i][j] = f[i-1][j];
if(nums[i]<=j) f[i][j] = fmin(f[i][j],f[i][j-nums[i]]+1);
}
}
printf("%d",f[n][m]);
return 0;
}
第四题
Leetcode1143最长公共子序列
int longestCommonSubsequence(char * text1, char * text2){
int n = strlen(text1),m = strlen(text2);
int f[n+10][m+10];
memset(f,0,sizeof(f));
for(int i = 1; i<=n; i++){
for(int j = 1; j <= m; j++){
f[i][j] = f[i-1][j-1];
if(text1[i-1] == text2[j-1]) f[i][j] = fmax(f[i][j],f[i-1][j-1]+1);
else{
f[i][j] = fmax(f[i][j],fmax(f[i-1][j],f[i][j-1]));
}
}
}
return f[n][m];
}
2017
第一题
注意:
大写字母+32变成小写字母
小写字母-32变成大写字母
第二题
#include <stdio.h>
#include <stdlib.h>
int cal(int n) //计算这个数的所有因子
{
int res = 0;
for(int i = 1; i < n; i++){
if(n%i == 0){
res = res + i;
}
}
return res;
}
int main()
{
for(int i = 2; i <= 20; i++){
printf("%d : %d \n",i,cal(i));
}
return 0;
}
第三题
相似例题:Leetcode1027最长等差数列
int longestArithSeqLength(int* nums, int numsSize){
int n = numsSize;
int f[1010][1010]; //f[i][d]表示以第i个数结尾,且公差为d的最长等差数列
//注意d可能是个负数,所以要有个偏移量
for(int i = 0; i <= n; i++){
for(int j = 0; j <= 1001; j++) f[i][j] = 1; //每个数至少自己能形成一个等差数列
}
for(int i = 1; i<= n; i++){
for(int j = 1; j < i; j++){
int d = nums[i-1] - nums[j-1] + 500; //可能有负数,记得偏移
f[i][d] = fmax(f[i][d],f[j][d] + 1);
}
}
int res = 1;
for(int i = 1; i <= n; i++){
for(int j = 0; j <= 1001; j++) res = fmax(res,f[i][j]);
}
return res;
}
第四题
并查集的思想,当然也可以直接暴搜
相似题目: Leetcode684冗余连接
/**
并查集来做,枚举边,不断把两个点加入到并查集中,当加入这个边之前,两个点已经是在一个集合里了
此时,这个边一定是让图成为环的边
*/
int p[1010];
int find(int x){
if(x != p[x]) p[x] = find(p[x]);
return p[x];
}
int* findRedundantConnection(int** edges, int edgesSize, int* edgesColSize, int* returnSize){
int n = edgesSize;
for(int i = 1; i <= n; i++) p[i] = i;
int *res = malloc(sizeof(int)*10);
*returnSize = 2;
for(int i = 0; i < n; i++){
int a = find(edges[i][0]), b = find(edges[i][1]);
if(a != b) p[a] = b;
else{
res[0] = edges[i][0];
res[1] = edges[i][1];
return res;
}
}
return res;
}
Leetcode889
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
struct TreeNode* dfs(int* preorder,int prel,int prer,int* postorder,int postl,int postr)
{
if(prel > prer) return NULL;
struct TreeNode* root = malloc(sizeof(struct TreeNode));
root->val = preorder[prel];
root->left = NULL;
root->right = NULL;
for(int i = postl; i < postr; i++){
if(postorder[i] == preorder[prel+1])
{
root->left = dfs(preorder,prel+1,prel+1+i-postl,postorder,postl,i);
root->right = dfs(preorder,prel+1+i-postl+1,prer,postorder,i+1,postr-1);
break;
}
}
return root;
}
struct TreeNode* constructFromPrePost(int* preorder, int preorderSize, int* postorder, int postorderSize){
int n = preorderSize;
return dfs(preorder,0,n-1,postorder,0,n-1);
}
Leetcode490迷宫
这个题是这个球在一直滚,选择了一个方向会直接滚到直到撞墙位置