蓝桥杯算法:数的分解

该博客探讨了一种算法问题,即如何将一个整数分解为三个不包含数字2和4的正整数之和。通过两层循环遍历所有可能的组合,同时确保数的不重复,博主详细分析了i、j、k之间的关系,以及它们的边界条件。在遍历过程中,博主发现了i的最大值为num/3-1,j的最大值为(num-1-(i%3))/2,并给出了相应的代码实现。最后,博主强调了实践在解决复杂问题中的重要性。
摘要由CSDN通过智能技术生成

【问题描述】
把 n分解成 3 个各不相同的正整数之和,并且要求每个正整数都不包
含数字 2和 4,一共有多少种不同的分解方法?
注意交换 3 个整数的顺序被视为同一种方法,例如 1999+3+18 和
1999+18+3 被视为同一种。
【输入格式】
输入一行包含一个整数 n。
【输出格式】
输出一行,包含一个整数,表示满足条件的分解方法种数。
【样例输入】
2019
【样例输出】
40785
【评测用例规模与约定】
对于所有评测用例,100 ≤ n ≤ 2500。


在遍历的时候,怎么能保证数不重复? 是本题比较难的一个点

做一个题,得有一个题的收获,这道题给我的收获是如果你无法想象出这道题的突破口在哪,去试,去看,实践出真知.

书归正传. 我们慢慢来捋.

这道题的整体思想是通过两层循环,i和j,然后通过这两个数就能得出第三个数k来.
然后我们想办法对这三个数进行筛选就可以了.

关于怎么让数不重复的原理,是这样的:

12 21 和 21 12有什么区别呢? 我们只需要保证后面的数比前面大,就不会重复了.

关键的点在于,这三个数该怎么去遍历呢?

在代码中,有这么几个点,得跟您说说是怎么来的:

在测试的时候,我让num等于100,遍历了所有的情况,来跟您讨论代码的特定实现,只有先把确定的问题找到具体实现,我们才能想,为n时的变化是什么.
1.k和j的关系是什么?k到什么时候就该停止?
我们可以看到,当i为1的时候,实际上是遍历了i为1,j从2开始,一直到98,因为i和k至少要有一个1,所以j最大为98.
但是值得注意的是,当遍历到我蓝色区域最终位置的时候,后面的内容实际上是在重复前面的结果,而我们题目说了,交换顺序算一个,也就是说,当k<=j的时候,我就该停止了.

k和j的关系我们讨论完了. 接下来


接下来我们讨论的是k的极限在哪? 不难看出,当i=1时,j最大为49.当i为2的时候,j最大为48,当i为3的时候,j最大为48,当i为4的时候,j最大为47.总之当i不断变大的时候,j一定会越来越小的.不过这个值的规律我没找出来. 这不妨碍我们找到它的极限,当i为1的时候,j为49. 而我们的num=100.意味着j的循环终止条件应该是num / 2 - 1. num=100时,最大情况为1 49 50. num=101(奇数)时,最大情况是1 49 51. 都满足这个条件.




接下来的问题是,i的极限在哪?
i < num / 3. 为什么是小于?而不是≤,又为什么是num / 3? 为什么把i的极限定为num / 3是让我最开始也很迷惑的问题.
首先k(第二个数)有一个前提,就是它肯定要比前一个数大.
i     j
1 2-99
2 3-98
3 4-97. 拿这一组来说,就应该是3 4,3 5,3 6,3 7,3 … 97. 如果你的j可以小于i,就会出现3 3(相同的抹去),3 2(3 2和i为2的时候,2 3重复了.),3 1(和i为1时,1 3重复了).
我们已经知道了j必须大于i,而且,k要大于j. k>j>i
那么i的极限是什么呢?当我们遍历到i为32的时候,发现只有一个值满足条件.

而当i为33的时候,一个满足条件的都没有了. 我们想想这是为什么呢? 当num为100的时候,我们要把num分为三个正整数,如果第一个数等于num的1/3的话,就是33,而第二个数不能比第一个数小,那么它最少也是34,而第三个数又不能比第二个数小,它最少是35. 但是这已经超过100了.

也就是说,当num为3的倍数的时候, 拿99举例,当i最大为num / 3 - 1. j最小为num / 3 .k最小为 num / 3 + 1. 即32 33 34
当num - 1为3的倍数的时候,拿100举例,当i最大为num / 3 - 1. j最小为num / 3 .k最小为 num / 3 + 2 (多加了一个1是把余数补上) 即 32 33 35.
当num - 2为3的倍数的时候,拿101举例,当i最大为num / 3 - 1. j最小为num / 3 .k最小为 num / 3 + 3 (多加了一个2是把余数补上) 即 32 33 36.
但是我们的循环实际上也不涉及到k的极限值,所以省了不少麻烦.

现在我们总结一下:

我们的目的是给我们一个整数,我们能把它分为三个互不相同的正整数,而且顺序转换的数为一种.

  1. 我们讨论了k和j之间的关系,j是变化的,k会随着j的变化而变化,我们发现当k≤j的时候,就该跳出当前的循环了.
  2. 接下来我们讨论了j的最大值问题. 当i为3的倍数的时候,如99,j最大值为(num - 1) / 2. 为 1 49 50.
    当i为%3余1的时候,如100,j最大值为(num - 2) / 2. 为 1 49 50.
    当i为%3余2的时候,如101,j最大值为(num - 3) / 2. 为 1 49 51.
    实际上是(num - 1 - (i % 3 )) / 2.
  3. 接下来我们讨论了i和j之间的关系,我们发现当j>i的时候,才有意义.
  4. 接下来我们讨论了i的最大值应该是什么? 我们发现i的最大值为num / 3 - 1

import java.util.Scanner;

public class resolutionNumber {
   public static void main(String[] args) {
   	Scanner input = new Scanner(System.in);
   	// 输入一个数
   	int num = input.nextInt();
   	// 用来计数
   	int count = 0;
   	// i从1到num / 3 - 1 我们上面已经讨论过了.
   	for (int i = 1; i <= num / 3 - 1; i++) {
   		// judge用来判断i是否包含2或4,如果包含,直接跳过即可.
   		if(judge(i)) 
   			continue;
   		// 第二个数从i + 1开始,终值我们在上面也已经讨论过了.  其实这里你干脆可以写j <= num. 因为下面如果k <= j了也会跳出. 所以这里的终止条件其实无所谓这么精确.
   		for (int j = i + 1; j <= (num - 1 - (i % 3 )) / 2; j++) {
   			// 得出k的值
   			int k = num - i - j;
   			
   			if(k <= j) {
   				break;
   			}
   			// 如果k和j包含2或4这个数字,跳过循环.
   			if(judge(k) || judge(j) ) 
   				continue;
   			// 否则就是满足条件的,三个数,而且互不相等,还不包含2或4.
   			count ++;
   			
   		}
   	}
   	
   }
   // true 为找到了
   public static boolean judge(int num) {
   // num + ""是把数字变成字符串类型. 然后分割一下存在nums数组里.
   // 接下来对比每一个字符,如果是2或4,就说明找到了,return true.
   	String[] nums = (num +"").split("");
   	for(String i : nums) {
   		if (i.equals("2") || i.equals("4")) {
   			return true;
   		}
   	}
   	return false;
   }
}


评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Jacob_云飞

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

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

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

打赏作者

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

抵扣说明:

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

余额充值