目录
每日一题:序列中删除指定数字
————来自牛客网BC124
大家好,我是小白,每日登山,顶峰相见
今天我来给大家讲解一道牛客网上的题,做了这么多题,感觉得和大家分享分享我的解题思路,若有错误,望大家斧正。
一、首先咱们看看题目及示例
这道题大致的意思就是让我们删除数组中一个指定的数字,并且不改变相对的顺序。
二、方法思路
(1)暴力覆盖法
顾名思义,暴力覆盖法就是用最朴实的方法,也是大家最常想到的方法,用被删除数字的后面那个数字来覆盖他。我们的思路就是首先找到那个数字,也就是需要一个循坏来遍历这个数组,然后让后面的那个数字来覆盖删除数字以达到删除效果,并且不改变数字的顺序。下面看代码
int main() {
int length = 0, arr[50] = { 0 }, target = 0,many=0;//先将要使用的数组和数组有用的长度以及要删除的目标数列出
scanf("%d", &length); //确定长度 //many为删除元素的个数
for (int i = 0; i < length; i++) {
scanf("%d", &arr[i]); //通过循环的方式将数据输入进数组
}
scanf("%d", &target); //确定删除的数据
many=deletemany(length, &arr, target);
int *arr2 = delete(length, &arr, target);//删除后序列,用arr2来接收,此时arr2未定义长度,用名字来代表第一个位置的地址
for (int i = 0; i < length - many; i++) // 然后接收
printf("%d ", arr2[i]);
return 0;
}
首先按照题目要求,输入数组的长度length,一个数组,以及我们想要删除的目标数字target。在数组中存入数据我们,使用最基本的for循环来进行输入,此时之前的length长度就可以用来控制循环的结束。然后我一般的解题习惯是写一个函数(我认为这是一个好习惯,可以重复用,并且使主函数简洁),这里我们先假设写好了一个能够满足这个程序的函数delete,然后数组删除完毕,接下里进行打印函数,因为函数经过删减,我们不知道数组中存在的数的个数,也就不知道打印结束的条件,此时我们另令一个函数deletemany,记录要删减的数字的个数。
两个函数如下:
int* delete(int length, int* arr, int target) {
for (int i = 0; i < length; i++) { //开始遍历
while (arr[i] == target&&i!=length-1) { //当第i+1个元素为要删减的数目时,用while的目的是,让连续的重复数都可以删除
for (int j = i; j < length-1; j++) {//而当用if时,再次进入循环的时候,此时arr[i]是删除数的下一位的数据
arr[j] = arr[j + 1]; //再次进入循环后,判断的就是原先i的后两位了,中间连续的就无法判断
}
length--;
}
}
return arr;//返回素组最好用地址,我此时取他地址返回,就能接收了
}
int deletemany(int length, int* arr, int target) {
int j = 0;
for (int i = 0; i < length; i++) {
if (arr[i] == target) j++; //每找到相同的数字,就用j来记录一次
}
return j;
}
deletemany函数容易理解。
我们来对delete函数,进行分析,首先要将数组的值传出去,我能想到的办法就是将地址传出去,然后用另一个数组来接收,也就是上面的arr2,所以函数的返回值类型是地址,然后数组中是数字,所以是整型。接下来这个方法的难点来了,每次删除数据时用后面一个数据来替代,那么当删除的数据是最后一个的时候呢?此时后面没有数据了,强行覆盖就会超过数据的长度,编码错误。我想的办法就是不管他,让他留在那里,当我检测他是最后一个的时候,我直接不进入循环,但是我deletemany函数已然会记录那个数字,最后打印的时候就不会打印出来。length--也很重要,这个可以记录删减后最后一个元素所在的位置。
(2)“另寻出路“”法
删减一个函数容易出错,那我们就重新找一个数组吧,不删减,在新的数组数组上记录下需要的数组就好了。我的思路是,创建一个新的空数组,要删减的数字就不加入,其余的的数字就加入。下面
int* delete(int length, int* arr, int target) {
int new[50];
return &new;
}
看代码
int* delete(int length, int* arr, int target) {
int new[50],j=0;
for (int i = 0; i < length; i++) { //遍历数组依然是必须的
if(arr[i]!=target) {
new[j] = arr[i];
j++;
}
}
return &new;
}
这个函数相对而言就简单很多啦
(3)不删而减法
第三种方法是我们不删除,但是我们将要删的数字记录下来,然后打印的时候不打印这个数字,这个方法更简单,但是却不是一个最佳方法,属于偷懒的方法,下面看代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main() {
int arr[50] = { 0 };
int length;
scanf("%d", &length);//行数
for (int i = 0; i < length; i++) {
scanf("%d", &arr[i]);//输入序列
}
int target; //要删的数字
scanf("%d", &target);
for (int i = 0; i < length; i++) {
if (arr[i] != target)
printf("%d ", arr[i]); //打印非0的数字
}
return 0;
}
三、总结
1、一个题的思维不应该拘泥于一种类型,我们应该打开思维,或许一种比一种简单
2、但是在寻找简单的方法途中,不能偷懒,去找程序要求的bug,而忽略了其本身给我们带来的思维锻炼
3、多亲自动手尝试,会发现很多你不曾注意的细节
4、不会写的时候一定要先思考,然后看看别人的代码,会给你带来很多的思考,集思广益,站在巨人的肩膀上才能成功
最后,蟹蟹大家的观看呀,走过路过,点个赞再走啦,小白的登山之路需要大家的鼓励才能攀高峰!