Java题解—1005 继续(3n+1)猜想

原题

当我们验证卡拉兹猜想的时候,为了避免重复计算,可以记录下递推过程中遇到的每一个数。例如对 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)的值,数字间用空格隔开。

6
3 5 6 7 8 11
结尾无空行

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

7 6
结尾无空行

解读

  • 关键数n要满足什么条件?
    除开数字自身,它重复计算偶数n\2或奇数(3n+1)\2时生成的一个数列,而待测验的一组数不在这个数列中。

1、反向移除不是关键数的:
反过来求,不是关键数n的(关键数要满足所有数字的“数列”都核对一遍,不是关键数只要在一个“数列”里就可以了)。
只要带测验的数,在任何一个“数列”中,就把它移除。这样剩下的就是关键数了。
这里我用列表来remove(num),不需数组的遍历移除

2、正向找:
把测试里的每个数生成的除开自身的数放一个集合里,再检验测试中的那些数字不在这个集合里,即该数字是关键数

代码

import java.util.*;

/**
 * 对任何一个正整数 n,如果它是偶数,那么把它砍掉一半;
 * 如果它是奇数,那么把 (3n+1) 砍掉一半。这样一直反复砍下去,最后一定在某一步得到 n=1
 */

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = Integer.parseInt(scanner.nextLine());
        String str=scanner.nextLine();
        //把测试样例存入列表
        String[] arr = str.split(" ");
//        List<String> list = Arrays.asList(arr);//这样生成的集合,只能读取,不能修改
        List<Integer> arrayList = new ArrayList<>();
        for(int j=0;j<arr.length;j++){
            arrayList.add(Integer.parseInt(arr[j]));
        }
        //把生成的数列里的每个数字,检验是否在测验样例中。如果在就移除
        for (int i=0;i<n;i++){
            int num=Integer.parseInt(arr[i]);//要用arr里的元素,因为list中的删除元素,长度变小arrayList.get(i)会报索引越界错误
            while(num!=1){
                if (num%2==0) {
                    num = num / 2;
                    if (arrayList.contains(new Integer(num))){
                        arrayList.remove(new Integer(num));
                    }
                }
                else {
                    num = (num * 3 + 1) / 2;
                    //把int转换成包装型,是因为List中的remove(int index)会与Collection中的remove(Object o)方法冲突
                    if (arrayList.contains(new Integer(num))){
                        arrayList.remove(new Integer(num));
                    }
                }
            }
        }
        //排序输出
        arrayList.sort(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return -Integer.compare(o1,o2);
            }
        });
      for (int i=0;i<arrayList.size();i++){
            if (i<arrayList.size()-1){
                System.out.print(arrayList.get(i)+" ");
            }else
                System.out.print(arrayList.get(i));
        }
    }
}

C++代码正向求解

#include<iostream>
#include<cstdio>
#include<algorithm> 
#include<vector>
#include<cstring>
using namespace std;
int flag[10000];
int main(){
	int K,i,j,a[101],t;
	scanf("%d",&K);
	for(i=0;i<K;i++){
		scanf("%d",&a[i]);//样例
	}
	memset(flag,0,sizeof(flag));
	sort(a,a+K);//起始地址和结束地址
	for(i=0;i<K;i++){
		t=a[i];
		while(t!=1){
		  if(t%2==0) t=t/2;
		  else t=(3*t+1)/2;
		  flag[t]=-1;//不能包括自身
		}
	}
	for(j=K-1;j>=0;j--){
		if(flag[a[j]]==0) 
		printf("%d ",a[j]);
	}
	return 0;
}
posted @ 2021-10-08 21:18  Infinite_V胜  阅读(48)  评论(0)    收藏  举报