一个整数可以由其他若干个连续整数的和表示(java)

题目的具体描述:
一个整数N,他可能等于比它小的若干个整数(大于2)相加。如果存在这样的连续整数,将他们输出,如果没有则不输出。
例: 整数18,18=5+6+7=3+4+5+6。所以输出[5 6 7],[3 4 5 6]。

这是一个公司给出的笔试编程题,当时我没做出来,当时一直在想总结规律,写出效率很高的代码,结果最后连一个可行方案都写出来。值得反思,当时时间有限,应该先写一个可行方案,在去考虑优化的,当时没有编译器进行调试,也不好测试优化的结果。
以下设:正整数为a,公差为d,项数为n。
这道题其实是一个公差为1的等差数列题,所以核心就是等差数列的公式:

a=((首项+末项)*n)/2=首项*n+[n*(n-1)*d]/2。

可以推出:

首项=a/n-(n-1)*d/2

那么对于一个整数a,它的等差数列最多能拥有几项?这里就要取极限了,对于正整数而言,1是最小的,所以假设整数N的等差数列的最大项数为max_n,其公差为d,那么a>=1max_n+[max_n(max_n-1)*1]/2(以1为首项,d为公差的等差数列),这个不等式就可以拿来作为边界判断,

而具体到本题,可以确定公差d=1,那么公式就可以化简:

首项=a/n-(n-1)/2
a=首项*n+[n*(n-1)]/2
边界不等式:(max_n-1)*max_n<=2a

公式都推完了,那么代码也就可以出来了:

import java.util.Scanner;

public class Main {
    private static void arithmetic_squence(int num){
        // 因为不确定项数n可以为多少,所以只能循环判断
        // 按照题目意思,最少都是有两项,所以i起点为2
        // i 的上限满足:i * (i + 1) <= 2 * num 
        for (int i = 2; i * (i + 1) <= 2 * num; i++) {
            int min=(num*2/i-i+1)/2; // 等差数列的首项,也为最小项,所以命名为min
            if (min*i+(i*(i-1)/2) == num) {
                // 打印结果
                for (int j = 0; j < i; j++) {
                    System.out.print(min+j);
                    System.out.print(" ");
                }
                System.out.println();
            }
        }
    }
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        while (scanner.hasNext()) {
            int num = scanner.nextInt();
            long startTime = System.currentTimeMillis();//获取当前时间
            arithmetic_squence(num);
            long endTime = System.currentTimeMillis();//获取当前时间
            System.out.println("程序运行时间:"+(endTime-startTime)+"ms");
        }
        scanner.close();
    }
}

其中有一个细节,首项=a/n-(n-1)/2,公式本身没错,但是代码里不能直接这么写,因为java的两个int数相除是会舍弃小数位,只保留整数位,那么(n-1)/2,就有可能出现小数,所以为了保证没有小数,需要先乘以2,做完差再除以2,即:

首项=[2*a/n-(n-1)]/2

这里还得说明:假如存在一个项数为N等差数列满足条件,那么根据公式计算的首项一定是一个整数。反之,计算出来的首项会是一个小数。那么java的int数计算后去掉小数点得到的首项,以此计算出来的等差数列和,会小于目标整数a,这边是我判断它是否满足条件的原因。

题目中还有个细节:整数大于2,所以做边界判断的时候,最小整数就不是1了,而是3,所以正确的边界判断条件应该是:

a>=3max_n+[max_n(max_n-1)*1]/2
化简:2a>=max_n(max_n-5)

所以弄明白了公式,随他把整数设置成多大,包括公差,也一样可以变成其他值。
对于整数100000000(一亿),有8个连续整数组合相加等于它,只需要80ms(算上输出到控制台的时间,和机器有关,我电脑配置很一般,约3500元的组装机)。首先,数字越大,需要循环的次数也就越多,一亿已经够大了,80ms这个效率,应该可以接受了吧。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lsjweiyi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值