PAT for Java:05-继续(3n+1)猜想:卡拉兹(Callatz)猜想

题目源地址:https://pintia.cn/problem-sets/994805260223102976/problems/type/7

继续(3n+1)猜想:

卡拉兹(Callatz)猜想已经在1001中给出了描述。在这个题目里,情况稍微有些复杂。

当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数。例如对 n=3 进行验证的时候,我们需要计算 3、5、8、4、2、1,则当我们对 n=5、8、4、2 进行验证的时候,就可以直接判定卡拉兹猜想的真伪,而不需要重复计算,因为这 4 个数已经在验证3的时候遇到过了,我们称 5、8、4、2 是被 3“覆盖”的数。我们称一个数列中的某个数 n 为“关键数”,如果 n 不能被数列中的其他数字所覆盖。 现在给定一系列待验证的数字,我们只需要验证其中的几个关键数,就可以不必再重复验证余下的数字。你的任务就是找出这些关键数字,并按从大到小的顺序输出它们。

输入格式:
每个测试输入包含 1 个测试用例,第 1 行给出一个正整数 K (<100),第 2 行给出 K 个互不相同的待验证的正整数 n (1<n≤100)的值,数字间用空格隔开。

输出格式:
每个测试用例的输出占一行,按从大到小的顺序输出关键数字。数字间用 1 个空格隔开,但一行中最后一个数字后没有空格。

输入样例:
6
3 5 6 7 8 11

输出样例:
7 6

这里本人采用了数组来做,代码如下:

import java.util.Scanner;

/*
 * 当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数。例如对 n=3 进行验证的时候,我们需要计算 3、5、8、4、2、1,则当我们对 n=5、8、
 * 4、2 进行验证的时候,就可以直接判定卡拉兹猜想的真伪,而不需要重复计算,因为这 4个数已经在验证3的时候遇到过了,我们称 5、8、4、2 是被 3“覆盖”的数。某个数 n为
 * “关键数”,如果 n 不能被数列中的其他数字所覆盖,找出这些关键数字,并按从大到小的顺序输出它们.
 */
public class Callatz2 {

	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);
		int k = sc.nextInt();
		int numberArr[] = new int[101];// 控制下标在<=100
		input(sc, k, numberArr);
		function(numberArr);
		output(numberArr);
		sc.close();
	}

	// 输出格式化
	private static void output(int[] numberArr) {
		boolean hasNum = false;
		for (int i = 100; i > 1; --i) {
			if (numberArr[i] == 1) {
				if (hasNum) {
					System.out.print(" ");
				}
				System.out.print(i);
				hasNum = true;
			}
		}
	}

	// 将覆盖的且在数组下标范围内值为1的下标的元素值赋0
	private static void function(int[] numberArr) {
		for (int i = 2; i <= 100; ++i) {
			if (numberArr[i] == 1) {
				int temp = i;
				while (temp != 1) {
					if (temp % 2 == 0) {
						temp /= 2;
						if (temp <= 100 && numberArr[temp] == 1) {
							numberArr[temp] = 0;
						}
					} else {
						temp = (3 * temp + 1) / 2;
						if (temp <= 100 && numberArr[temp] == 1) {
							numberArr[temp] = 0;
						}
					}
				}
			}
		}
	}

	// 将待测数据作为数组下标,数组值赋为1
	private static void input(Scanner sc, int k, int[] tempNumber) {
		for (int i = 0; i < k; ++i) {
			int number = sc.nextInt();
			tempNumber[number] = 1;
		}
	}

}

具体思路:

(1)先将录入的数据作为数组下标并将其元素值设为1,表示这个下标是原始数据;

(2)然后读取值为1的下标进行Callatz判断,将其过程中产生的覆盖数先判断是否小于等于100然后与值为1的数组下标比对,true则将这个下标对应的值赋值为0,表示该下标(原始数据)被覆盖了;

(3)剩下的值为1的即表示没有被覆盖,逆序打印下标即可,记得处理空格。

注意:

(2)过程中产生的覆盖数要判断是否小于等于100再进行赋值操作,否则定义数组时务必要保证数据能够有空间可存,不要小看才1-100,实测过程中产生的最大数不止224=(3*99+1)*3+1,大概设置数组空间为3000才够用(其实浪费空间),而采用先判断后加入则只需101即可(最大下标即为数据最大值100,对应数组空间即101,因为最大下标=(length-1)),经过PAT编译器时,前面几个通过了,只有后面一个或2个没过,很大可能就是这个问题,亲测!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值