问题描述
小蓝对一个数的数位之和很感兴趣, 今天他要按照数位之和给数排序。当 两个数各个数位之和不同时, 将数位和较小的排在前面, 当数位之和相等时, 将数值小的排在前面。
例如, 2022 排在 409 前面, 因为 2022 的数位之和是 6, 小于 409 的数位 之和 13 。
又如, 6 排在 2022 前面, 因为它们的数位之和相同, 而 6 小于 2022 。
给定正整数 n,m, 请问对 1 到 n 采用这种方法排序时, 排在第 m 个的元 素是多少?
输入格式
输入第一行包含一个正整数 n 。
第二行包含一个正整数 m 。
输出格式
输出一行包含一个整数, 表示答案。
样例输入
13
5
样例输出
3
样例说明
1 到 13 的排序为: 1,10,2,11,3,12,4,13,5,6,7,8,91,10,2,11,3,12,4,13,5,6,7,8,9 。第 5 个数为 3 。
评测用例规模与约定
对于 30%30% 的评测用例, 1≤m≤n≤3001≤m≤n≤300 。
对于 50%50% 的评测用例, 1≤m≤n≤10001≤m≤n≤1000 。
对于所有评测用例, 1≤m≤n≤1061≤m≤n≤106 。
运行限制
最大运行时间:3s
最大运行内存: 512M
经验:
如果自己要用快排,能不用结构体就不用结构体,因为自己很容易出错
如果在自己的电脑上调试,不出结果,可以分步调试。
如果有些情况不知道怎么调试,还有一个原因是运行超时了,那就要修改自己的代码。
学到处理数位和的方法,用while循环。
写函数时,是为了方便,同时也降低了时间复杂度
写函数的时候,不要多次定义同一个变量,否则会报错
巧妙答案:
#include <stdio.h>
int sum(int a)
{
int j=0;
while(a)
{
j+=a%10;
a/=10;
}
return j;
}
int main()
{
// 请在此输入您的代码
long long int n,m,i,t,j=1;
scanf("%lld\n%lld",&n,&m);
long long int a[n];
for(i=1;i<=54;i++) //最大位数之和是6*9
for(t=1;t<=n;t++) //这样既保证了按顺序,运用了分类排序的思想
{
if(sum(t)==i)
{
a[j++]=t;
}
}
printf("%d",a[m]);
return 0;
}
我自己写的
#include <stdio.h>
#include <stdlib.h>
cmp(const void *a,const void *b)
{
//这个处理方式和之前的直接来不太一样,这样更直观
int numa=*(int *)a;
int numb=*(int *)b;
int suma=sum(numa);
int sumb=sum(numb); //这样numa,numb的类型会和suma,sumb的类型一样的
if(suma!=sumb)
return suma-sumb; //数位之和小的排在前面
else
return numa-numb; //数位之和相等时,数值小的排在前面
}
int sum(int t)
{
{int sum=0,y;
while(t!=0)
{
y=t%10;
t=t/10;
sum=sum+y;
}
return sum;
}
}
int main()
{
int n,m,i,j,t,y;//为余数
scanf("%d",&n);
scanf("%d",&m);
int a[n];
for(i=0;i<n;i++)
{
a[i]=i+1;
}
qsort(a,n,sizeof(int),cmp);
printf("%d",a[m-1]); //因为这里设置下标是从零开始的,所以会有点不同
}
这个代码是完全ok的,可以通过全部测试点,用的是快排,时间复杂度没有这么高
#include <stdio.h>
#include <stdlib.h>
int sum(int t) //记得要有返回值
{int sum=0,y;
while(t!=0)
{
y=t%10;
t=t/10;
sum=sum+y;
}
return sum;
}
int main()
{ //用数组来存每个数
int m,n,a[1000000],tmp,j,k,i;
scanf("%d",&n);
scanf("%d",&m);
for(i=1;i<=n;i++)
{
a[i]=i;
}
for(k=1;k<n;k++)
{
for(j=k+1;j<=n;j++) //不要改一个变量,就改一个地方,其他位置不改
{
int sum1=sum(a[k]); //sum1来存k的数位和3
int sum2=sum(a[j]); //不能是sum(k)和sum(j)
{
if(sum1>sum2||(sum1==sum2&&a[k]>a[j]))
{
tmp=a[k];
a[k]=a[j];
a[j]=tmp;
}
}
}
}
printf("%d",a[m]);
}
不足:
1.时间复杂度会比较大
还有几个测试点无法通过
注意:
交换排序里面一定要写,sum(a[k]),sum(a[j]),而不是sum(k)和sum(j),因为下面交换的是数组,不要搞错了
#include <stdio.h>
#include <stdlib.h>
int sums(int x){
int sum=0;
while(x){
sum+=x%10;
x/=10;
}
return sum;
}
int main(int argc, char *argv[])
{
// 请在此输入您的代码
int n;
int m;
int s1,s2;
int a,b;
int temp;
scanf("%d",&n);
scanf("%d",&m);
int arr[n];
for(int i=0;i<n;i++){
arr[i]=i+1;
}
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
a=sums(arr[i]);
b=sums(arr[j]);
if(b<a||(b==a&&arr[j]<arr[i])){
temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
}
printf("%d",arr[m-1]);
return 0;
}
这个是我在网上看到的一个和我的方法极为相似的做法
也是还有7个点无法通过,但错误原因是运行超时
明明两个思路一样,但是为什么错误的点不太一样,寻求帮助???