排序练习一:数位排序

问题描述

小蓝对一个数的数位之和很感兴趣, 今天他要按照数位之和给数排序。当 两个数各个数位之和不同时, 将数位和较小的排在前面, 当数位之和相等时, 将数值小的排在前面。

例如, 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≤mn≤300 。

对于 50%50% 的评测用例, 1≤m≤n≤10001≤mn≤1000 。

对于所有评测用例, 1≤m≤n≤1061≤mn≤106

运行限制

  • 最大运行时间:3s

  • 最大运行内存: 512M

经验:

  1. 如果自己要用快排,能不用结构体就不用结构体,因为自己很容易出错

  1. 如果在自己的电脑上调试,不出结果,可以分步调试。

如果有些情况不知道怎么调试,还有一个原因是运行超时了,那就要修改自己的代码。

  1. 学到处理数位和的方法,用while循环。

  1. 写函数时,是为了方便,同时也降低了时间复杂度

写函数的时候,不要多次定义同一个变量,否则会报错

巧妙答案:

#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.时间复杂度会比较大

  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个点无法通过,但错误原因是运行超时

明明两个思路一样,但是为什么错误的点不太一样,寻求帮助???

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值