(Java)详解 L1-006 连续因子

思路

(概念) 最长连续因子的个数 和 最小的连续因子序列📏

  • 因为我们要记录最长的连续因子序列,因此我们需要一个变量记录我们解题过程中得到的序列长度;同时,为了保证最终得到的是最长的那个,所以一旦遇到更长的序列,我们就要立刻更新这个变量的值
  • 题目中说的“最小连续序列”的意思是:在所有最长因子序列中,最小的那一个序列。
  • 确定“最小连续序列”的方法是:遍历2 ~ √n(从小到大),第一个“最长因子序列”就是“最小连续序列”。

求解步骤✅

  • 遍历2 ~ √n 间的数字,记录遍历过程中遇到的数字的累乘值,并判断累乘值是否能被 n 整除: * 如果能整除,再判断当前“收集到的”数字的个数(或者说长度)有没有比以前的长度大,有的话就要更新长度并且记录当前这个序列的起点(方便后续输出“最小的连续因子序列”),否则继续往后遍历;
    • 如果不能整除,停止循环(不要再往后遍历了),更改遍历的起点,继续寻找最长因子序列。
  • 输出最长连续因子的个数 :遍历完之后,用于存储序列长度的遍历值就已经是“最长连续因子的个数”了
  • 输出最小的连续因子序列:上述过程中我们以及得到最长序列的起点以及它的长度了,这点也就很容易解决了

🚨 难点 🚨

1. 为什么只需要遍历到√n就可以了?
  • 首先,n = √n * √n;假设 a > √n,那么,a * √n 就一定大于 n
  • 其次,题目让我们找连续的因子序列,假设你现在找到的序列中有一个数字y 大于 √n ,那么,为了满足连续,这段序列中一定存在另外一个数字 x >= √n,那 x * y 肯定大于 n了
2. 到底该用什么类型变量存储 题目给的整数 以及 遍历过程中用于记录因子序列累乘值?
  • 题目给的整数n的范围是(1<N<2^31),很明显 int型就足够了,因为int最大值是 (2 ^ 31) - 1;
  • 对于“用于记录因子序列累乘值”的变量:其实这个取决于你第二层for循环的“终止条件”(也就是中间那个条件表达式),或者说取决于你遍历的范围
    • 如果遍历范围是 2 ~ √n,那么int型就足够了,参考上一个难点,我们可以确定,在这个遍历范围内,一定不会有累乘值大于 n
      ,既然n用int存储都足够了,那它肯定也够用了; * 如果遍历范围是 2 ~ n,那累乘值就有可能超过n ,也就有可能超过 int
      型能表达的最大值,所以,这个遍历范围下,应该用long类型保存累乘值。
3. 为什么if(n % sum == 0)不可以写成 if(n % j == 0) ?🤔
  • 因为这题的核心是 找出乘积能够被 n 整除的因子序列,然后再从其中找长度最大的那个;
  • 用if(n % j == 0)作为判断语句,存在一个“漏洞”:假设 n % a = 0 ,n % b = 0,但 n % (a * b) 不一定也等于 0。(数学渣,目前还想不明白怎么证明,如果有大佬知道,感谢解答~
  • 但是,用if(n % sum == 0)做判断语句,得到的因子序列的乘积一定能被n 整除!
4. 为什么第一层for循环“累加器”是 i++而不是 i += len?
  • 如果是i += len ,假设我们遇到了下图的情况:

在这里插入图片描述

n % (2 * 3 * 4) == 0,但是 n % (2 * 3 * 4 * 5) != 0。如果将起点改为6,那么就会忽略(3 *
4 * 5)、(4 * 5)这些组合,存在“漏洞”,因此选择 i++

在这里插入图片描述

代码

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int len = 0,start = 0,sum = 0;
        for (int i = 2; i <= Math.sqrt(n); i++) {
            sum = 1;
            for (int j = i; j <= Math.sqrt(n); j++) {
                sum *= j;
                if (n % sum == 0) {
                    if( j - i + 1 > len) {
                        len = j - i + 1;
                        start = i;
                    }
                }else break;
            }
        }
        if (start == 0) {
            start = n;
            len = 1;
        }
        System.out.println(len);
        for (int i = 0; i < len; i++) {
            if(i == len - 1) System.out.print(start + i);
            else System.out.print(start + i + "*");
        }
    }
}

💖💖💖 如果觉得有用,不如点个关注!💖💖💖

在这里插入图片描述

  • 24
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值