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:开灯问题
解题思路
- 用一个数组来模拟灯的状态
- 刚开始灯都是关着的
- 让每个人去关他对应的灯
- 当所有人都做完的时候
- 检查还有那些灯开着,并打印
解题方法
从人的角度出发
#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不会用数组
解题思路
- 把输入的数的每一位都存放到数组当中
- 给数组用选择法从小到大排序
- 打印数组
解题方法
#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,分母是正整数
- 用循环来求和,当Sn大于k时结束循环
- 打印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;
}
易错点
- Sn的值可能会超出float的精度范围,所以在写小数点的题时要注意数据的精度是否满足要求
- 当循环结束时,i还会加1,所以我们输出的是i - 1的值
5. 问题E:判断升序
解题思路
- 如果一个数组是升序,那么它们相邻两个元素的大小必定是前面小,而后面大
- 如果是前面大,后面小就一定不是升序,类似冒泡的过程
解题方法
#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:行排序
解题思路
- 算出各行的平均值
- 按各行的平均值排序
- 打印排序之后的数组
解题方法
#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:摘陶陶
解题思路
- 题目要求摘取的顺序按照输入的“苹果够到的最大高度”的顺序来摘
- 所以我们给苹果的高度和陶陶的高度排个序
- 然后给每个苹果找一个更它最接近的陶陶
- 只要陶陶的高度不为0,我们就可以摘,摘了之后m的值减1
- 当遍历完整个苹果的数组之后打印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;
}
标签:11,-------,int,题解,high,++,low,include,swap
From: https://www.cnblogs.com/lwj1239/p/17810921.html