【820复试】编程题/填空题(一)

1.完美乘法:a*b=c,a、b、c中只出现0~9的数字,且每个数字在这个等式中只出现一遍。要求输出所有符合条件的式子和式子总数。

输出格式:

“a * b = c”

“x” //x为符合条件的式子数量

#include<bits/stdc++.h>
using namespace std;

int main(){
	int count=0;
	int f[10],s[3];
	/*
	这里讲为什么两个for循环这样设置
	因为只能出现10个数字
	c的取值必须是5位数
	那么a和b的取值要么是1位*4位,要么是2位*3位
	不会再出现其他情况了
	即使是手写代码,也一定要注意不能出现时间复杂度高于5*10^8这个量级
	不然会超出1s的执行时间,大多数OJ就不会通过这样的代码
	*/
	for(int i=1; i<9999; i++){
		for(int j =1; j<99; j++){
			int key = 0;
			for(int x=0; x<10; x++) f[x]=0; //初始化出现的数字数组
			int k = i*j;
			s[0]=i; //存储暴力搜索的三个数
			s[1]=j;
			s[2]=k;
			for(int x=0; x<3; x++){ //这三个数分别记录已出现的数字
				int y=s[x];
				while(y>0){
					int t = y%10;
					f[t]++;
					y=y/10;
				}
			}
			for(int x =0; x<10; x++)
				if(f[x]!=1) key++; //若已存储数字超过1 或者为0 说明不符合题意
			if(key ==0){ //若为key=0 则说明符合题意
				count ++;
				cout << k <<" = "<< i<< " * "<< j<<endl;
			}
		}
	}
	cout<<count;
	return 0;
} 
2.求数组中第k小的数

解题思想:利用快速排序做一个升序序列,直接输出第k个数即可。

//代码如下:
#include<iostream>
using namespace std;

void quick_sort(int a[], int l, int r){
	if(l>=r) return;
	int i=l,j=r-1;
	int x = a[r];
	while(i<j){
		while(i<j && a[i]<x) i++;
		while(i<j && a[j]>=x) j--;
		int t= a[i];
		a[i]=a[j];
		a[j] =t;
	}
    //最后再移动枢纽
	if(a[i]>= a[r]){
		int t= a[i];
		a[i]=a[r];
		a[r] =t;
	}
	else i++;
	if(i)
		quick_sort(a,l,i-1);
	quick_sort(a,i+1,r);
}
int main(){
	int a[1000];
	int n,k;
	cin >> n>>k;
	for(int i=0; i<n; i++) cin >> a[i];
	quick_sort(a,0,n-1); //做升序即可 
	for(int i=0; i<n;i++) cout <<a[i]<<' ';
	cout << endl;
	cout << a[k];
	
	return 0;
}
3.【约瑟夫环问题】n个人围成圈,从第一个人开始1~3报数,数到3的人退出,直到只有1个人,问剩下来的这个人的编号是多少。

输入样例:100

输出样例:91

//代码一:本代码只输出最后剩下来的这个人的编号
#include<bits/stdc++.h>
using namespace std;
int n, m;
int main()
{
	cin >> n >> m;
	int p = 0;
	for (int i = 2; i <= n; i++) {
		p = (p + m) % i;
	}
	cout << p + 1;
	return 0;
}

若是要依次输出退出的人的编号,那么代码又是什么样的呢?

//代码一:
//利用STL容器中的queue很容易就实现了
#include<bits/stdc++.h>
using namespace std;
queue<int>q;
int cnt;
int main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; ++i){
		q.push(i);
	}
	while (!q.empty()){
		cnt++;
		int x = q.front();
		q.pop();
		if (cnt == k){
			cnt = 0;
			cout << x << " ";
		}
		else q.push(x);
	}
	return 0;
}
//代码二:
//构造单循环链表
#include<iostream>
using namespace std;
struct Node {
	int id;
	Node* next;
	Node(int x) :id(x), next(NULL) {};
};
Node* Head = new Node(1);
Node* End = Head;
int n, m;
int cnt = 1;
void add(int k){ //单循环链表关键步骤
	Node* p = new Node(k);
	End->next = p;
	End = End->next;
}
int main(){
	cin >> n >> m;
	for (int i = 2; i <= n; ++i){
		add(i);
	}
	End->next = Head;
	Node* t = Head;
	while (t){
		if (++cnt == m){
			cout << t->next->id << " ";
			t->next = t->next->next;//删除操作
			if (t == t->next)break; //特判一下
			cnt = 1;
		}
		t = t->next;
	}
	cout << t->id;
	return 0;
}
4.输出一个数n的所有质因数;
//法一:递归法
#include<iostream>
using namespace std;
void prim(int n, int i){
	if(i>n) return;
	if(n%i==0){
		cout << i<<' ';
		prim(n/i,i);
	}
	if(n>0 && n%i!=0) prim(n, i+1);
}

int main(){
	int x;
	cin >> x;
	prim(x,2);
	
	return 0;
}
变体1:输出两个数的最大公因数gcd,最小公倍数lcm。
#include<bits/stdc++.h> 
using namespace std;

int gcd(int a, int b){ //辗转相除法 要求a<b
	if(a%b!=0) return gcd(b,a%b);
	return b;
}

int main(){
	int a,b;
	cin >> a>> b;
	if(a<b) swap(a,b);
	cout << gcd(a,b)<<endl;
    cout <<"lcm(a,b):"<<a/gcd(a,b)*b;
	return 0;    
}
变体2:输入n个数字,求出其最小公倍数。
#include<bits/stdc++.h> 
using namespace std;

int x[10010];int gcd(int a, int b){ //辗转相除法 要求a<b
	if(a%b!=0) return gcd(b,a%b);
	return b;
}

int lcm(int a, int b){
	if(a<b) swap(a,b);
	return a/gcd(a,b)*b;
}

int main(){
	int n; //n Numbers
	cin >> n;
	for(int i=0; i<n; i++) cin >> x[i];
	int k=x[0];
	for(int i=1; i<n; i++){
		k = lcm(k,x[i]);
	}
	cout << k;
	return 0;    
}

5.输出范围为n以内的所有质数,并统计数量。
//主要代码如下
//CodeBegin
int sieve(int n){
    int i,j,k;
    k=0;
    vis[0]=vis[1]=1;
    for(i=2;i<=n;i++){
        if(vis[i]==0) prime[k++]=i;
        for(j=i+i;j<=n;j+=i) vis[j]=1;
    }
    return k;
}
//CodeEnd

#include<stdio.h>
#include<string.h>//memset函数的头文件

//设定一个宏,定义数组大小
#define maxn 20010

int vis[maxn];//vis用来判断数字是否访问过
int prime[maxn];//prime用来存储筛选出来的素数

int sieve(int n){
    int i,j,k;
    k=0;//i用来控制逐个访问,j用来第二轮标记,k用来标记prime数组位置
    memset(vis,0,sizeof(int)*maxn);
    vis[0]=vis[1]=1;
    for(i=2;i<=n;i++){
        if(vis[i]==0)//这个数是目前最小的,且未被访问过的
            prime[k++]=i;//因此这个数是素数
        for(j=2;i*j<=n;j++)//j表示倍数,从两倍开始倍增,直到上界为止
            vis[i*j]=1;//将倍数标记为已访问
    }
    return k;//返回范围内素数的个数
}

void print(int k)//打印结果函数
{
    int i;
    for(i=0;i<k;i++){
        printf("%5d ",prime[i]);//每个数字占5个宽度
        if((i+1)%5==0)//每五个为一组换行
            printf("\n");
    }
    printf("\n\n");
}

int main(){
    int n;//求n以内的素数
    int k;//保存返回的素数个数
    while(scanf("%d",&n)!=EOF){
        k=sieve(n);
        if(k==0)
            printf("(1-%d]范围内没有素数\n",n);
        else
            printf("(1-%d]范围内的素数有:\n",n);
        print(k);
    }
}

6.链表逆置

如果是填空题,注意多想些情况就好,如果是编程题就随意发挥,正确即可。

最好就是直接用头插法

如果填空题中不是头插法,那就举例子,例子中赋值好理解代码。

7.求2/1+3/2+5/4+8/5+…的前n项之和。

//找规律+模拟

#include<bits/stdc++.h> 
using namespace std;
int main(){
	double i=1,j=2,m,ans=0;
	int n;
	cin >> n;
	for(int k=1; k<=n; k++){
		ans += j/i;
		m = i+j;
		i=j;
		j=m;
	}
	cout << ans;
	return 0;    
}


8.从1-100中找出符合一下条件的数,输入数字d,找到该数和该数的平方中都含有输入的数字d
//模拟即可
#include<bits/stdc++.h> 
using namespace std;
int main(){
	int d;
	cin >> d;
	for(int i=1; i<101; i++){
		int x=i, y=i*i;
		bool flag1=false, flag2=false;
		while(x){
			int m = x%10;
			if(m==d){
				flag1=true;
				break;
			}
			x /= 10;
		}
		while(y){
			int m = y%10;
			if(m==d){
				flag2=true;
				break;
			}
			y /= 10;
		}
		if(flag1&&flag2){
			cout << i<<' '<<i*i<<endl;
		}
	}
	return 0;    
}
9.输入两个字符串str1,str2,在str1中删除str2中出现过的字符,最后输出str1。

三种做法:

//法一:指针法:
#include <stdio.h>

void deleteChars(char *str1, const char *str2) {
    if (str1 == NULL || str2 == NULL) {
        return;
    }
    char *p1 = str1;
    char *p2 = str2;
    while (*p2 != '\0') {
        char *temp = p1;
        char *q = p1;
        while (*q != '\0') {
            if (*q != *p2) {
                *temp = *q;
                temp++;
            }
            q++;
        }
        *temp = '\0';
        p2++;
    }
}
int main() {
    char str1[] = "abcdef";
    const char str2[] = "bd";
    
    deleteChars(str1, str2);
    
    printf("%s\n", str1); // 输出: "acef"
    
    return 0;
}

//法二:数组暴力求解
#include <stdio.h>
#include <string.h>

void removeChars(char str1[], char str2[]) {
    int i, j, k;
    int len1 = strlen(str1);
    int len2 = strlen(str2);

    // 标记str2中字符出现情况
    int flag[256] = {0};

    // 标记str2中字符
    for (i = 0; i < len2; i++) {
        flag[str2[i]] = 1;
    }

    // 移动str1中不在str2中出现的字符
    j = 0;
    for (i = 0; i < len1; i++) {
        if (!flag[str1[i]]) {
            str1[j++] = str1[i];
        }
    }
    str1[j] = '\0';
}

int main() {
    char str1[100], str2[100];
    scanf("%s", str1);
    scanf("%s", str2);

    // 调用函数删除字符
    removeChars(str1, str2);

    // 输出结果
    printf("Resulting string: %s\n", str1);

    return 0;
}

//法三:桶数组记录/map记录求解 C/C++都可以做
#include <stdio.h>
#include <string.h>

#define MAX_CHAR 256

void deleteChars(char str1[], char str2[]) {
    int bucket[MAX_CHAR] = {0}; // 初始化桶数组

    // 在桶数组中标记str2中出现的字符
    for (int i = 0; str2[i] != '\0'; i++) {
        bucket[(int)str2[i]] = 1;
    }

    int index = 0;
    // 遍历str1,将不在桶数组中出现的字符添加到结果字符串中
    for (int i = 0; str1[i] != '\0'; i++) {
        if (bucket[(int)str1[i]] == 0) {
            str1[index++] = str1[i];
        }
    }
    str1[index] = '\0'; // 在末尾添加字符串结束标志
}

int main() {
    char str1[100], str2[100];

    printf("Enter str1: ");
    scanf("%s", str1);
    printf("Enter str2: ");
    scanf("%s", str2);

    deleteChars(str1, str2);

    printf("Result: %s\n", str1);

    return 0;
}

10.如果有两个数,每个数的所有约数(除了本身外)的和等于对方,那么成为这两个数为互满数。求出30000内所有的互满数并输出。
#include <stdio.h>
#define MAX_NUM 30000
// 计算一个数的所有约数的和
int sumOfDivisors(int num) {
    int sum = 1; // 包括1作为约数
    for (int i = 2; i <= num / 2; i++) {
        if (num % i == 0) {
            sum += i;
        }
    }
    return sum;
}
int main() {
    for (int i = 1; i <= MAX_NUM; i++) {
        int sum1 = sumOfDivisors(i); // 第一个数i的所有约数之和为sum1
        int sum2 = sumOfDivisors(sum1); // 第一个数i的所有约数之和sum1的所有约数之和为sum2		
        // 检查是否成为互满数
        if (sum2 == i && sum1 != i) { //sum1!=i条件是为了去重
            printf("(%d, %d)\n", i, sum1);
        }
    }
    return 0;
}

11.输入一个字符串,将连续相同的字符删减为一个,以"*"作为字符串结尾。
//典型的用do...while循环来实现
#include <stdio.h>
int main() {
    char ch;
    char old=' ',new_;
	scanf("%c",&ch);
	do{
		new_ = ch;
		if(new_==old) continue;
		old = new_;
		putchar(ch);
	}while(scanf("%c",&ch) && ch!='*');
    return 0;
}

12.输入字符串s1和s2,输入m,在字符串s1的第m个位置插入s2,并输出插入后的s1字符串。
#include <stdio.h>
#include <string.h>

void insertString(char s1[], char s2[], int m) {
    int len1 = strlen(s1);
    int len2 = strlen(s2);
    // 检查输入合法性
    if (m < 0 || m > len1) {
        printf("Invalid position!\n");
        return;
    }
    // 将s2插入s1的第m个位置
    //先把中间为len2的空留出来
    for (int i = len1; i >= m; i--) {
        s1[i + len2] = s1[i]; // 后移len2个位置
    }
    //在中间长度为len2的空填充str2
    for (int i = 0; i < len2; i++) {
        s1[m + i] = s2[i]; // 插入s2
    }
    s1[len1 + len2] = '\0'; // 添加字符串结束标志
}

int main() {
    char s1[100], s2[100];
    int m;
    printf("Enter s1: ");
    scanf("%s", s1);
    printf("Enter s2: ");
    scanf("%s", s2);
    printf("Enter the position to insert s2 into s1: ");
    scanf("%d", &m);
    insertString(s1, s2, m);
    printf("Result: %s\n", s1);
    return 0;
}

13.读程序、写出功能并且指出需要改正的地方的题目。

需要注意:

①**数组边界检查:**在处理数组时,要确保不会越界访问数组元素,这可能导致程序崩溃或产生未定义的行为。

如数组大小固定的话,写出“数组应该用动态内存的方法,在输入n以后在动态申请数组的大小”。

在动态内存分配的情况下,要确保释放分配的内存,以防止内存泄漏。

一些边界验证

在插入字符串时,应该确保目标数组足够大,以防止溢出。

冒泡排序的两个循环体的循环条件分别是什么?注意到了吗?

冒泡排序多种写法的总结如下:

/*
需要注意的是每个循环的循环终止条件的不同
可以完成相同的排序 但是过程可以不同
*/
//传统冒泡排序1
for (i = 0; i < n-1; i++) {
        //bool flag = false;
        for (j = 0; j < n-i-1; j++) {
            if (arr[j] > arr[j+1]) {
                int temp = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = temp;
                //flag = true;
            }
        }
    	//if(!flag) break; //本轮没交换 说明排序完成
    }

// 改变内层循环终止条件的冒泡排序2
void bubbleSort(int arr[], int n) {
    for (int i = 0; i < n-1; i++) {
        for (int j = i+1; j < n; j++) {
            if (arr[i] > arr[j]) {
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }
}

//改变内层循环终止条件的冒泡排序3
void bubbleSort(int arr[], int n) {
    for (int i = 0; i < n - 1; i++) {
        for (int j = n - 1; j > i; j--) {
            if (arr[j - 1] > arr[j]) {
                int temp = arr[j - 1];
                arr[j - 1] = arr[j];
                arr[j] = temp;
            }
        }
    }
}

输入缓冲区溢出: 使用了scanf函数读取字符串输入,然而这种方式可能导致输入缓冲区溢出。

更安全的做法是使用fgets函数来读取字符串输入,并且要注意处理换行符。

④待补充…

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值