2023年11月第一周题解-------数组

1. 问题A:LY学长的随机数

解题思路

第一种思路是先去重后排序

第二种思路是先排序再去重

解题方法

暴力遍历

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#define N 10

void quickSort(int *a, int low, int high);//快速排序 
void swap(int *a, int low, int high);//交换a[low]和a[high]的值 
int* partition(int *a, int low, int high);//把a中low到high的数分类,小于的在左边,等于的在中间,大于的在右边 
int rm(int* nums, int numsSize){//给数组去重
    int k=numsSize,i,j,m;
 
    for(i=0;i<k;i++)
    {
        for(j=i+1;j<k;j++)
        if(nums[i]==nums[j])
        {
            for(m=j+1;m<k;m++)
            {
                nums[m-1]=nums[m];
            }
            k--;
            j=i;
        }
    }
    return k;
}

int main() {
    int n = 0;
    
    scanf("%d", &n);
    
    int *p = (int*)malloc(sizeof(int) * n);
    
    for (int i = 0; i < n; i++) {
        scanf("%d", p + i);
    }
    
    int size = 0;
    
    size = rm(p, n);//O(N^3)
    
    quickSort(p, 0, size - 1);//O(Nlog(N))
    
    printf("%d\n", size);
    
    for(int i = 0; i < size; i++) {
        printf("%d ", p[i]);
    }

    return 0;
}
void quickSort(int *a, int low, int high)
{
	int *p = NULL;//存储等于基准值的左右边界 
	
	if ( low >= high) {//如果只有一个值不用排序就直接结束排序 
		return ;
	}
	
	swap(a, low + rand() % (high - low + 1), high);
	p = partition(a, low, high);
	quickSort(a, low, p[0] - 1);
	quickSort(a, p[1] + 1, high);
	free(p);
}
void swap(int *a, int low, int high)
{
	int t = 0;
	
	t = a[low];
	a[low] = a[high];
	a[high] = t;
}
int* partition(int *a, int low, int high)
{
	int l = low - 1;
	int r = high;
	int i = low;
	int key = a[high];
	while(i < r) {
		if (a[i] < key) {
			swap(a, l + 1, i);
			i++;
			l++;
		}
		else  if ( a[i] > key){
			swap(a, r - 1, i);
			r--;
		}
		else {
			i++;
		}
	}
	swap(a, r, high);
	int *p = (int *)malloc(sizeof(int ) * 2);
	p[0] = l + 1;
	p[1] = r;
	return p;
}

暴力的去找数组中相同的数,找到了就从数组中删除。看rm函数我们可以发现这个方法的时间复杂度为O(N3),复杂度太高了,那么我们思考可不可以优化呢很明显是可以的。

双指针

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#define N 10

void quickSort(int *a, int low, int high);//快速排序 
void swap(int *a, int low, int high);//交换a[low]和a[high]的值 
int* partition(int *a, int low, int high);//把a中low到high的数分类,小于的在左边,等于的在中间,大于的在右边 
int rm(int* nums, int target, int numsSize){//去重O(N)
	int i, j;//双指针
    for (i = 0, j = 0; i < numsSize; i++){
    	if (nums[i] != target) {
    		nums[j++] = nums[i];
		}
	}
	nums[j] = target;//再把这个数赋值到数组的最后
	
	return j + 1;//返回去重后的数组长度
}

int main() {
    int n;
    
    scanf("%d", &n);
    
    int *p = (int*)malloc(sizeof(int) * n);
    
    for (int i = 0; i < n; i++)
    {
    	scanf("%d", p + i);
	}
	
	int size = n;
	
	for (int i = size - 1; i >= 0; i--) {//O(N)
		size = rm(p, p[i], size);//O(N^2)
	}
	
	quickSort(p, 0, size - 1);//O(NlogN)
	
	printf("%d\n", size);
	
	for (int i = 0; i < size; i++) {
		printf("%d ", p[i]);
	}
	
    return 0;
}
void quickSort(int *a, int low, int high)
{
	int *p = NULL;//存储等于基准值的左右边界 
	
	if ( low >= high) {//如果只有一个值不用排序就直接结束排序 
		return ;
	}
	
	swap(a, low + rand() % (high - low + 1), high);
	p = partition(a, low, high);
	quickSort(a, low, p[0] - 1);
	quickSort(a, p[1] + 1, high);
	free(p);
}
void swap(int *a, int low, int high)
{
	int t = 0;
	
	t = a[low];
	a[low] = a[high];
	a[high] = t;
}
int* partition(int *a, int low, int high)
{
	int l = low - 1;
	int r = high;
	int i = low;
	int key = a[high];
	while(i < r) {
		if (a[i] < key) {
			swap(a, l + 1, i);
			i++;
			l++;
		}
		else  if ( a[i] > key){
			swap(a, r - 1, i);
			r--;
		}
		else {
			i++;
		}
	}
	swap(a, r, high);
	int *p = (int *)malloc(sizeof(int ) * 2);
	p[0] = l + 1;
	p[1] = r;
	return p;
}

这个方法本质是对去重函数的优化,让去重函数的时间复杂度降低到了O(N),所以这个算法的时间复杂度是O(N2),还是太高了,那么还可不可以优化到O(N)呢?

哈希表

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#define N 10

void quickSort(int *a, int low, int high);//快速排序 
void swap(int *a, int low, int high);//交换a[low]和a[high]的值 
int* partition(int *a, int low, int high);//把a中low到high的数分类,小于的在左边,等于的在中间,大于的在右边 

int main() {
    int n;
    int hash[10000] = {0};
    int m = 0;
    
    scanf("%d", &n);
    
    int *p = (int*)malloc(sizeof(int) * n);
    
    for (int i = 0; i < n; i++)
    {
    	int t = 0;
    	scanf("%d", &t);
    	if (hash[t] == 0) {//如果是0代表不在哈希表中,是第一次出现放进数组中
    		p[m++] = t;
		}
    	hash[t]++;
	}
	
	int size = m;
	
	quickSort(p, 0, size - 1);//O(NlogN)
	
	printf("%d\n", size);
	
	for (int i = 0; i < size; i++) {
		printf("%d ", p[i]);
	}
	
    return 0;
}
void quickSort(int *a, int low, int high)
{
	int *p = NULL;//存储等于基准值的左右边界 
	
	if ( low >= high) {//如果只有一个值不用排序就直接结束排序 
		return ;
	}
	
	swap(a, low + rand() % (high - low + 1), high);
	p = partition(a, low, high);
	quickSort(a, low, p[0] - 1);
	quickSort(a, p[1] + 1, high);
	free(p);
}
void swap(int *a, int low, int high)
{
	int t = 0;
	
	t = a[low];
	a[low] = a[high];
	a[high] = t;
}
int* partition(int *a, int low, int high)
{
	int l = low - 1;
	int r = high;
	int i = low;
	int key = a[high];
	while(i < r) {
		if (a[i] < key) {
			swap(a, l + 1, i);
			i++;
			l++;
		}
		else  if ( a[i] > key){
			swap(a, r - 1, i);
			r--;
		}
		else {
			i++;
		}
	}
	swap(a, r, high);
	int *p = (int *)malloc(sizeof(int ) * 2);
	p[0] = l + 1;
	p[1] = r;
	return p;
}

利用哈希表来帮我们去重,每次输入就判断key有没有再哈希表中,如果输入的数在哈希表中代表是重复的数,因此不把它放进我们的数组中。这样当输入结束时我们数组中的数一定是没有重复的。那么我们就只要排序了。这样我们的时间复杂度O(NlogN)就已经很好了。当然这个哈希表的实现不是很聪明,如果数据大了就不行。

2. 问题B:开灯问题

解题思路

  1. 用一个数组来模拟灯的状态
  2. 刚开始灯都是关着的
  3. 让每个人去关他对应的灯
  4. 当所有人都做完的时候
  5. 检查还有那些灯开着,并打印

解题方法

从人的角度出发

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>

int main(int argc,char *argv[])
{
   int n =  0, k = 0;
   
   scanf("%d%d", &n, &k);//n代表有几盏灯,k代表有几个人 
   
   //0代表灯是关着的,1代表灯是开着的 
   bool p[100] = {0}; 
   
   for ( int i = 1; i <= k; i++) {
       for (int j = 0; j < n; j++) {
           if ( (j + 1) % i == 0) {//把是第i个人倍数的灯给打开或者关上 
               p[j] = !p[j];//或者异或1 
           }
       }
   }
   
   for ( int i = 0; i < n; i++) {
       if ( p[i] == 1) {//如果是1代表是开着的,打印 
           printf("%d ", i + 1);
       }
   }
   
	return 0;
}

3. 问题C:LY不会用数组

解题思路

  1. 把输入的数的每一位都存放到数组当中
  2. 给数组用选择法从小到大排序
  3. 打印数组

解题方法

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>

int main(int argc,char *argv[])
{
   int m = 0;
   
   scanf("%d", &m);//输入m的值 
   
   int size = 100;
   int *p = (int*)malloc(sizeof(int) * size);//开辟一个数组 
   
   //把每一位的数字取出来 
	for ( int i = 0; i < size; i++)  {
		p[i] = m % 10;
		m /= 10;
	}
	
	//选择法排序 
	for (int i = 0; i < size - 1; i++) {
		int min = i;
		for ( int j = i + 1; j < size; j++) {
			if ( p[min] > p[j])	 {
				min = j;
			}
		}
		if ( min != i) {//如果要交换 
			p[min] ^= p[i];
			p[i] ^= p[min];
			p[min] ^= p[i];
		}
	}
	
	//打印结果 
	for ( int i = 0; i < size; i++)  {
		printf("%d ", p[i]);
	}
   
	return 0;
}

4. 问题D:级数求和

解题思路

  1. 观察这个数列发现它的分子都是1,分母是正整数
  2. 用循环来求和,当Sn大于k时结束循环
  3. 打印n - 1

解题方法

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>

int main(int argc, char *argv[])
{
   int k = 0;
   
   scanf("%d", &k);
   
  double sum = 0;//float精度不够 
  int i = 1;
  
    for ( i = 1; sum <= (double)k; i++ ) 
    {
       sum += 1.0 / i;
    }
   
   printf("%d", i - 1);//循环结束时i多加了1
	return 0;
}

易错点

  1. Sn的值可能会超出float的精度范围,所以在写小数点的题时要注意数据的精度是否满足要求
  2. 当循环结束时,i还会加1,所以我们输出的是i - 1的值

5. 问题E:判断升序

解题思路

  1. 如果一个数组是升序,那么它们相邻两个元素的大小必定是前面小,而后面大
  2. 如果是前面大,后面小就一定不是升序,类似冒泡的过程

解题方法

#include <stdio.h>

int main()
{
    int n = 0;
    
    scanf("%d", &n);
    
    int *p = (int*)malloc(sizeof(int) * n);
    
    for (int i = 0; i < n; i++){
        scanf("%d", p + i);
    }
    
    int i = 0;
    
    for (; i < n - 1; i++) {
        if ( p[i] > p[i + 1]) {
            break;
        }
    }
    
    if (i >= n - 1) {
        printf("YES");
    }
    else {
        printf("NO");
    }
    
    return 0;
}

6. 问题F:行排序

解题思路

  1. 算出各行的平均值
  2. 按各行的平均值排序
  3. 打印排序之后的数组

解题方法

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>

int main(int argc, char *argv[])
{
	int n = 0;
	
	scanf("%d", &n);
	
	int *p = (int*)malloc(sizeof(int) * n * n);//开辟一个n*n的一维数组来模拟二维数组 
	
	//赋值
	for (int i = 0; i < n; i++)
		for ( int j = 0; j < n; j++) {
			scanf("%d", p + i * n + j); 
		}
	
	float average[n];//存放各行的平均值 
	
	//计算各行的平均值 
	for (int i = 0; i < n; i++){
		float sum = 0;
		for ( int j = 0; j < n; j++) {
				sum += p[i * n + j];
		}
		average[i] = sum / n;
	}
	//用选择排序对各行的平均值进行排序		
	for ( int i = 0; i < n - 1; i++) {
		int min = i;
		for ( int j = i + 1; j < n; j++) {
			if ( average[min] > average[j]) {
			    min = j;
			}
		}
		
		if ( min != i) {
			//把最小的一行和第i行进行交换 
		    for ( int m = 0; m < n; m++) {
		        p[i * n + m] ^= p[min * n + m];
		        p[min * n + m] ^= p[i * n + m];
		        p[i * n + m] ^= p[min * n + m];
		    }
		    //最小的平均值和第i个平均值进行交换 
		    float t = 0.0;
		    t = average[i];
		    average[i] = average[min];
		    average[min] = t;
		}
	}
	
	//打印结果 
	for ( int i = 0; i < n; i++){
	    for (int j = 0; j < n; j++)
	        printf("%d ", p[i * n + j]);
	    putchar('\n');
	}
	    
	return 0;
}

7. 问题G:摘陶陶

解题思路

  1. 题目要求摘取的顺序按照输入的“苹果够到的最大高度”的顺序来摘
  2. 所以我们给苹果的高度和陶陶的高度排个序
  3. 然后给每个苹果找一个更它最接近的陶陶
  4. 只要陶陶的高度不为0,我们就可以摘,摘了之后m的值减1
  5. 当遍历完整个苹果的数组之后打印m的值

解题方法

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdbool.h>
#define ll long long
#define sc scanf
#define pr printf

void quickSort(int *a, int low, int high);
void swap(int *a, int low, int high);//交换a[low]和a[high]的值 
int* partition(int *a, int low, int high);//把a中low到high的数分类,小于的在左边,等于的在中间,大于的在右边

int main(int argc, char *argv[]) 
{
	int n,m;
	
	sc("%d%d", &n, &m);//输入苹果和陶陶的值
	
	int *apple = (int*)malloc(sizeof(int) * n);//开辟存放苹果高度的数组
	int *tao = (int*)malloc(sizeof(int) * m);//开辟存放陶陶高度的数组

    //输入苹果的高度
	for (int i = 0; i < n; i++)
	{
		sc("%d", apple + i);
	}

     //输入陶陶的高度
	for (int i = 0; i < m; i++)
	{
		sc("%d", tao + i);
	}

    //给苹果和陶陶的高度排序
	quickSort(tao, 0, m - 1);
	quickSort(apple, 0, n - 1);

    //给每个苹果找一个可以摘到的陶陶
	for (int i = n - 1; i >= 0; i--)
	{
		for (int j = m - 1; j >= 0; j--)
		{
			if (tao[j] != 0 && apple[i] > tao[j])//如果陶陶的高度不为0且苹果可以摘到陶陶
			{
				m--;//陶陶的数量减1
				tao[j] = 300;//设置为最大的高度,下一循环就不会摘到相同的陶陶
				break;//因为一个苹果只能摘一个陶陶所以跳出,去看下一个苹果
			}
		}
	}
	
	printf("%d", m);//打印剩下的陶陶
	
    return 0;
}
void quickSort(int *a, int low, int high)
{
	int *p = NULL;//存储等于基准值的左右边界 
	
	if ( low >= high) {//如果只有一个值不用排序就直接结束排序 
		return ;
	}
	
	swap(a, low + rand() % (high - low + 1), high);
	p = partition(a, low, high);
	quickSort(a, low, p[0] - 1);
	quickSort(a, p[1] + 1, high);
	free(p);
}
void swap(int *a, int low, int high)
{
	int t = 0;
	
	t = a[low];
	a[low] = a[high];
	a[high] = t;
}
int* partition(int *a, int low, int high)
{
	int l = low - 1;
	int r = high;
	int i = low;
	int key = a[high];
	while(i < r) {
		if (a[i] < key) {
			swap(a, l + 1, i);
			i++;
			l++;
		}
		else  if ( a[i] > key){
			swap(a, r - 1, i);
			r--;
		}
		else {
			i++;
		}
	}
	swap(a, r, high);
	int *p = (int *)malloc(sizeof(int ) * 2);
	p[0] = l + 1;
	p[1] = r;
	return p;
}
posted @   lwj1239  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示