题目:
分三步完成:第一步是全排列数字,第二步是将乘号放入不同的位置,第三步是判断得到的乘积是否是不同的数字。
第一步使用最熟悉的套路,没有重复元素的全排列数组来完成,和2014年的六角填数重复,该代码后为六角填数代码。然后在套路的输出那里执行第二步。
第二步我想的是依次对数字做10的倍数的乘积,每次有8种乘积方式,想实现方法的时候想的比较杂乱。而老师的做法也是这个思路,不过非常清晰:先分别调用两个数组转整数的函数,乘号的位置用传的参数不同(起始位置和结束位置不同)来表示。然后再将两个整数相乘。后面再自己实现数组转整数的函数。
第三步我想的是依次对数字做10的倍数的除法,这样做的时间复杂度比较高。老师的做法是,将得到的乘积结果(整数)转成字符串,先判断得到的结果是不是9个数(剪枝),然后依次将字符存入hashset利用hashset是一个不允许有重复元素的集合的性质,通过最后的hashset长度是否为9来判断是否有重复数字(这里要排除数字中有0的情况)
联想:
- 字符串转整数:Integer.parseInt(array[i])
- 整数转字符串: Sring s = x + “”
- 数组转字符串:Arrays.toString(newArray)
小知识点:
- int x; String s = x+"";//就可以把整数变成字符串
- 使用HashSet来判断字符串内是否有重复:
- HashSet 基于 HashMap 来实现的,是一个不允许有重复元素的集合。
- HashSet 允许有 null 值。
- HashSet 是无序的,即不会记录插入的顺序。
- int indexOf(String str) :返回第一次出现的指定子字符串在此字符串中的索引,如果此字符串中没有这样的字符,则返回 -1。
坑:
-
最后的数字里面不能有0
-
最后答案除以二
-
关于Java中形参与实参的理解:https://blog.csdn.net/czh500/article/details/88636612:
1)形参为基本类型时,对形参的处理不会影响实参。
2)形参为引用类型时,对形参的处理会影响实参。
3)String,Integer,Double等immutable类型的特殊处理,可以理解为值传递,形参操作不会影响实参对象。
代码:
import java.util.HashSet;
import java.util.Set;
public class NineNumbers {
static int ans;
static void permutation(int[] a, int p)// 参数是否需要数组(如果数组是static全局变量就不需要)
{
if (p == 9) {
for (int i = 1; i <= 8; i++) {
int i1 = atoi(a, 0, i);// 不取结尾(i),这样跟下面就没有重复数字
int i2 = atoi(a, i, 9);
if (check(i1 * i2))
ans++;
}
}
for (int i = p; i < 9; i++) {
swap(a, p, i);// p可以取8,跟a[i]交换
// int t = a[i]; a[i] = a[p]; a[p] = t;
permutation(a, p + 1); // 但p+1为9时一次全排完成,进入if
swap(a, p, i);
// t = a[i]; a[i] = a[p]; a[p] = t;
}
}
static void swap(int[] a, int i, int j) { int temp = a[i]; a[i] = a[j]; a[j] = temp; }
static int atoi(int[] a, int i, int j) {
int sum = 0;
int p = 1;
for (int k = j - 1; k >= i; k--) {
sum += p * a[k];
p = p * 10;
}
return sum;
}
static boolean check(int i) {
String s = i + "";
if (s.length() != 9 || s.indexOf("0") > -1) {
return false;
}
Set<Character> set = new HashSet<Character>();
for (int j = 0; j < s.length(); j++) {
set.add(s.charAt(j));
}
return set.size() == 9;
}
public static void main(String[] args) {
int[] a = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
permutation(a, 0);
System.out.println(ans / 2);
}
}
六角填数的全排列代码,老师的做法是把if里面的加法都先写出来赋给不同变量,用变量代替加法从而代码更加清晰:
public class SixAngle {
static int[] a = {2, 4, 5, 6, 7, 9, 10, 11, 12};
static void permutation(int k) {
if(k == a.length) {
if(3+8+a[0]+a[1] == 1+a[0]+a[2]+a[3] && 1+a[0]+a[2]+a[3] == 8+a[2]+a[4]+a[5]) {
if(8+a[2]+a[4]+a[5] == 3+a[7]+a[6]+a[5] && 3+a[7]+a[6]+a[5] == a[8]+a[6]+a[4]+1) {
if(a[8]+a[6]+a[4]+1 == a[8]+a[7]+a[1]+a[3]) {
System.out.println(a[0]);
return;
}
}
}
}
for(int i = k; i < a.length; i++) {
int t = a[k]; a[k] = a[i]; a[i] = t; //a[k]和其后的所有a[i]交换都会交换一次
permutation(k + 1);//子数组进行全排列
t = a[k]; a[k] = a[i]; a[i] = t;//为了下一次交换,这次交换回来
}
}
public static void main(String[] args) {
permutation(0);
}
}