先上代码:
import java.util.Scanner;
/**
* 项目名称:HankSon
* 类名称:HankSon
* 类描述:解决包括hankson问题等多个问题的程序
* 创建人:百里梦想
* 创建时间:2020年3月30日 下午9:29:17
* 完成时间:2020年4月01日 下午1:40:03
* @version 3.0.0
*/
public class HankSon {
static Scanner scanner = new Scanner(System.in);
//辗转相除法求最大公约数算法
public static int gcd(int a,int b) {
int temp;
while(b>0) {
temp=a%b;
a=b;
b=temp;
}
return a;
}
//最小公倍数的算法
public static int lcm(int a,int b) {
int temp;
for(temp = a; ; temp ++) {
if(temp % a == 0 && temp % b == 0) {
break;
}
}
return temp;
}
//将最大公约数算法结合穷举法将所有满足条件的数字放入一个字符串
public static String gcd_output(int a,int b,int Max) {
String S = "";
for (int x = 1 ; x <= Max ; x ++) {
if (gcd(x,a) == b) {
S = S.concat(Integer.toString(x)).concat(" ");
}
}
return S;
}
//将最小公倍数算法结合穷举法将所有满足条件的数字放入一个字符串
public static String lcm_output(int a,int b) {
String S = "";
for (int x = 1 ; x <= b ; x ++) {
if (lcm(x,a) == b) {
S = S.concat(Integer.toString(x)).concat(" ");
}
}
return S;
}
//HankSon逆问题主函数
public static void HankSon_output() {
int exit_flag = 0; //异常处理值,如果数据异常,将改为1并结束程序
int data_length = 0; //存放输入的数据的组数
int a0 = 0,a1 = 0,b0 = 0,b1 = 0; //存放输入的数据
int k = 0; //存放最终的解的个数
String gcd_string = "";
String lcm_string = "";
System.out.println("请输入要输入数据的组数:");
data_length = scanner.nextInt();
int[] data = new int[4*data_length + 1];
for(int i = 0;i <data_length; i++) {
System.out.println("请输入第" + (i+1) + "组数据");
try {
data[i*4+1] = scanner.nextInt();
data[i*4+2] = scanner.nextInt();
data[i*4+3] = scanner.nextInt();
data[i*4+4] = scanner.nextInt();
}
catch(Exception e) {
System.out.println("输入错误!请输入数字!");
System.exit(1);
}
if(data[i*4+1] == 0 || data[i*4+2] == 0 || data[i*4+3] == 0 || data[i*4+4] == 0) {
exit_flag = 1;
System.out.println("数据错误!请重新输入!(任意数值皆不能为0)");
System.exit(exit_flag);
}
if(data[i*4+1] % data[i*4+2] != 0 || data[i*4+4] % data[i*4+3] != 0) {
exit_flag = 1;
System.out.println("数据错误!请重新输入!(a0能被a1整除,b1能被b0整除)");
System.exit(exit_flag);
}
}
for(int j = 0;j <data_length; j++) {
a0 = data[j*4+1];
a1 = data[j*4+2];
b0 = data[j*4+3];
b1 = data[j*4+4];
// System.out.println("公约数序列:" + gcd_output(a0,a1,b1));
// System.out.println("公倍数序列:" + lcm_output(b0,b1));
int Max = Math.max(Math.max(a0, a1),Math.max(b0, b1));
gcd_string = gcd_output(a0,a1,Max);
lcm_string = lcm_output(b0,b1);
int length_gcd = gcd_string.length();
int length_lcm = lcm_string.length();
if(length_gcd < length_lcm) {
String[] gcd_part = gcd_string.split(" ");
int length_gcd_temp = gcd_part.length;
// System.out.print("重合的序列数字为:");
for(int i = 0; i < length_gcd_temp ; i ++) {
if(lcm_string.contains(gcd_part[i].toString())) {
// System.out.print(part1[i] + " ");
k++;
}
}
}
else {
String[] lcm_part = lcm_string.split(" ");
int length_lcm_temp = lcm_part.length;
// System.out.print("重合的序列数字为:");
for(int i = 0; i < length_lcm_temp ; i ++) {
if(gcd_string.contains(lcm_part[i].toString())) {
// System.out.print(part2[i] + " ");
k++;
}
}
}
System.out.println(k);
k = 0;
}
}
//求N个数的最大公约数的函数
public static int _gcdN(int[] a,int length)
{
int temp = gcd(a[0],a[1]);
for(int i = 1;i < length - 1;i ++) {
temp = gcd(temp,a[i + 1]);
}
return temp;
}
//求N个数的最大公约数的主调用函数
public static void gcdN_output() {
int N = 0;
System.out.println("请输入要求最大公约数的数的个数(N):");
try {
N = scanner.nextInt();
}
catch(Exception e){
System.out.println("输入错误!请输入数字!");
System.exit(1);
}
if(N <= 1) {
System.out.println("输入错误!请输入大于2的数。");
System.exit(1);
}
int[] data = new int[N];
System.out.println("请依次输入每个数的值:");
for(int i = 0;i < N;i ++) {
System.out.println("第" + (i+1) + "个数为:");
data[i] = scanner.nextInt();
}
System.out.println("它们的公约数为:" + _gcdN(data,N));
}
//求N个数的最小公倍数的函数
public static int _lcmN(int[] a,int length)
{
int temp = lcm(a[0],a[1]);
for(int i = 1;i < length - 1;i ++) {
temp = lcm(temp,a[i + 1]);
}
return temp;
}
//求N个数的最小公倍数的主调用函数
public static void lcmN_output() {
int N = 0;
System.out.println("请输入要求最小公倍数的个数(N):");
try {
N = scanner.nextInt();
}
catch(Exception e){
System.out.println("输入错误!请输入数字!");
System.exit(1);
}
if(N <= 1) {
System.out.println("输入错误!请输入大于2的数。");
System.exit(1);
}
int[] data = new int[N];
System.out.println("请依次输入每个数的值:");
for(int i = 0;i < N;i ++) {
System.out.println("第" + (i+1) + "个数为:");
data[i] = scanner.nextInt();
}
System.out.println("它们的公倍数为:" + _lcmN(data,N));
}
public static void _continue(boolean _continue) {
char flag = 'Y';
System.out.println("是否继续?(Y 或 N)");
flag = scanner.next().charAt(0);
if(flag == 'Y' || flag == 'y' || flag == '1') {
_continue = true;
}
else {
System.out.println("感谢您的使用!");
System.exit(1);
}
}
public static void main(String[] args) {
boolean _continue = true;
int flag = 0;
while(_continue) {
System.out.println("*************1.求N个数的最大公约数*************");
System.out.println("**********************************************");
System.out.println("*************2.求N个数的最小公倍数*************");
System.out.println("**********************************************");
System.out.println("***************3.HankSon逆问题****************");
System.out.println("请输入你想执行的选择(1-3):");
try {
flag = scanner.nextInt();
}
catch(Exception e) {
System.out.println("输入错误!请输入数字!");
System.exit(1);
}
if(flag > 3 || flag < 1) {
System.out.println("输入错误!请重新输入!");
System.exit(1);
}
switch(flag) {
case 1:
gcdN_output();
_continue(_continue);
break;
case 2:
lcmN_output();
_continue(_continue);
break;
case 3:
HankSon_output();
_continue(_continue);
break;
default:
}
}
}
}
**算法设计:
1、基础算法设计:
- ①gcd函数通过使用辗转相除法来获得任意两数的最大公约数。
- ②lcm函数通过使用最小公倍数的定义来获得任意两数的最小公倍数。
2、gcdN_output函数设计:
- ①题目要求输入N个数并求他们的最大公约数,可以先建立一个数组,并将所有的输入数据存入这个数组中,并且得到数组的长度。
- ②将数组和数组的长度作为参数调用_gcdN函数,_gcdN函数每进行一次两两求最大公约数后,数组的长度减1,直到数组长度为1,返回最后的最大公约数。
- ③针对异常数据进行处理,对非数字型数据和N小于2的数据进行异常处理,当出现上述问题时,程序将直接结束。
3、lcmN_output函数设计:
- 同gcdN_output函数设计思路一样,仍然使用了数组和两两计算的方法,只不过将参数传递给了_lcmN函数。
4、HankSon_output函数设计:
-
①首先建立四个变量,分别是a0 a1 b0 b1用来存储用户输入的四个数据。
-
②其次建立一个变量,data_length用来存储用户输入的数据组数。
-
③再建立一个变量,命名为k,用来存储当前数据组的解的个数。
-
⑤该函数还另外调用了两个函数:
-
I. gcd_output:
※该函数通过将gcd函数和穷举法结合起来使用后,以数据组中最大的数为循环上限,输出所有符合条件的解,并将它们存放在一个字符串内,每个解之间使用空格隔开。 -
II. lcm_output:
※该函数通过将lcm函数和穷举法结合起来使用后,以数据组中的b1为循环上限,输出所有符合条件的解,同样将它们存放在一个字符串内,每个解之间使用空格隔开。 -
⑥数据处理:通过data_length可以得知用户将要输入的数据组数,程序将以此为依据,建立一个专门存放数据的数组data[],并开始循环输入数据,data[]从索引1开始以每4个存储空间为界限,存放数据。如果数据中出现非数字型数据,0,a0不能被a1整除,b1不能被b0整除的情况,程序将会直接退出。
-
⑦结果计算:经过数据处理我们将会得到一个data[]和data_length,这一步将从0开始循环,直到data_length停止。循环中,会将data[]中的数据重新提取出来,分别赋给a0
a1 b0
b1,然后将它们分别传递给gcd_output函数和lcm_output函数。经过这两个函数的计算,将会得到两个分别存放着gcd和lcm解的字符串。 -
⑧结果数据处理:通过对比两个字符串的长度,会将字符串短的数据列通过split方法分成数组,并根据数组的长度开始循环,如果数组中的值存在于另一个字符串中,那么最终的解将增加1。循环结束后,输出最终解的个数。
5、主函数设计:
- 主函数采用菜单设计,通过输入不同的菜单序号以执行不同的功能,如果输入的菜单序号不符合规范,程序将抛出错误提示,并直接停止。每次执行完某个模块的功能后,都将调用_continue函数,来判断用户是否继续程序。**