我需要检查两个数组是否包含相同的数字。所以:
[1,1,2] and [1,2,2] = false;
[2,3,1] and [1,2,3] = true;
[1,2,4] and [1,3,2] = false;
[1,1,4] and [1,2,3] = false;
现在不知怎的,这有效,乘法:
boolean areSimilar(int[] a, int[] b) {
int s1 = 1, s2 = 1;
for(int i = 0; i < a.length; i++) {
s1 *= a[i];
s2 *= b[i];
}
return s1 == s2;
}
但是,如果我将*=
替换为+=
,那么只需更新一些,[1,1,4] and [1,2,3]
将返回true而不是false(显然,因为它将返回6等于6)。
所以我的问题是,我可以确保乘法是故障证明吗? 或者通过乘法可能2个数组可能包含不同的数字但是具有相同的产品?
答案 0 :(得分:3)
我很确定该产品可能与其中的differenz数字相同。示例:[9 1 2] [18 1 1]
我建议采用不同的解决方案。
首次对阵列进行排序时,您可以检查每个数字是否相同。
答案 1 :(得分:2)
不,乘法不是&#34;故障证明&#34;从这个意义上说。
明显的反例是两个数组都包含 0 (零)作为其元素之一的反例。无论其他元素如何,产品将始终为0。即使没有任何元素为零,也很容易找到更多的反例。
使用乘法只是&#34;安全&#34; 当且仅当数组中的数字是相同数字的prime factors时。素数因子化是唯一的,元素相乘的顺序无关紧要。
编辑:
在这里,我提出了一个解决实际问题的方法,即检查两个数组是否包含相同的元素,忽略顺序。
正如评论中所讨论的那样,虽然它理论上(渐近)慢,但answer by dnswlt中提出的基于排序的方法似乎在实践中效率更高,如果你不关心克隆阵列所暗示的内存消耗。
我最初提出的解决方案具有内存消耗较低,渐近运行时间较短的优点,以及概念适用于其他类型元素的事实(特别是对于包含不可比较的元素的数组,因此无法对其进行排序)。
方法是为每个数组构造一个Map
。这个Map
将数组的每个元素映射到它出现在数组中的次:
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class SameNumbersInArray
{
public static void main(String[] args)
{
System.out.println(areSimilar(
new int[] { 1, 1, 2 },
new int[] { 1, 2, 2 }));
System.out.println(areSimilar(
new int[] { 2, 3, 1 },
new int[] { 1, 2, 3 }));
System.out.println(areSimilar(
new int[] { 1, 2, 4 },
new int[] { 1, 3, 2 }));
System.out.println(areSimilar(
new int[] { 1, 1, 4 },
new int[] { 1, 2, 3 }));
System.out.println(areSimilar(
new int[] { 1, 1, 1, 4 },
new int[] { 1, 1, 4 }));
System.out.println(areSimilar(
new int[] { 1, 1, 1, 4 },
new int[] { 1, 1, 4, 1 }));
}
private static boolean areSimilar(int[] a, int[] b) {
Map<Integer, Long> frequenciesA = IntStream.of(a).boxed()
.collect(Collectors.groupingBy(
Function.identity(), Collectors.counting()));
Map<Integer, Long> frequenciesB = IntStream.of(b).boxed()
.collect(Collectors.groupingBy(
Function.identity(), Collectors.counting()));
return frequenciesA.equals(frequenciesB);
}
}
测试用例的输出是
false
true
false
false
false
true
但是,对于int[]
数组,基于排序的方法在实践中更有效(可能是由于基于计数的方法进行了昂贵的装箱转换)。
答案 2 :(得分:2)
正如其他人所指出的那样,显然既不增加也不增加。典型的基于排序的解决方案如下所示:
boolean areSimilar(int[] a, int[] b) {
if (a.length != b.length) {
return false;
}
int[] aSorted = a.clone();
Arrays.sort(aSorted);
int[] bSorted = b.clone();
Arrays.sort(bSorted);
return Arrays.equals(aSorted, bSorted);
}
请注意,我使用clone()
来确保您的原始数组保持不变。如果这无关紧要,您可以直接对a
和b
进行排序。
答案 3 :(得分:1)
不,乘法不是故障证明。
考虑数组{1,1,6}和{1,2,3}。它们具有相同的产品(6),但数字不同。
答案 4 :(得分:1)
无法添加或乘法。
您正在尝试将N个32位数映射到单个32位数。那就是数据压缩。您不能将32 * N位信息装入32位,就像您不能将N升水放入一升瓶中一样(当然,除非N为1)。
有时,您可以利用数据的某些属性,以便您需要少于32*N
位的信息:例如,如果您知道数字介于0和15之间,则每个数字只需要4位。但在一般情况下,你不能。
很简单,总会出现“碰撞”,其中两个不同的数组映射到相同的值。
你可以做的是说数字肯定不相同。您可以使用乘法或加法方法:如果两个数组的乘积或总和不同,它们肯定不一样;如果是,你必须进一步检查以确定数字是否相同。
这是hashCode
方法的基础:正确实施后,hashCode
可以确定两个实例是否相等;如果你想知道他们 是否相等,你必须使用equals
方法。
答案 5 :(得分:0)
乘法不是故障证明。 这只是一个快速检查。有点像一个简写,找到一个比较是否值得做。校验和(这里检查乘法)类型的检查。
[0,x,y,z,...] == [..a,b,0,c ...]总是
答案 6 :(得分:0)
为什么不结合总和和产品? (相当于下面的java代码)
val r = scala.util.Random
// 10 digits produce to few collisions to control by hand:
// def arr = Vector (r.nextInt (10), r.nextInt (10), r.nextInt (10))
def arr = Vector (r.nextInt (3), r.nextInt (3), r.nextInt (3))
// first idea: a*b*c + a+b+c, but 3,0,0 and 2,1,0 produce
// product 0 and sum 3
// def checksum (v: Vector[Int]) : Int = v.product + v.sum
// so we just add 1 to every digit
def checksum (v: Vector[Int]) : Int = (v(0)+1)*(v(1)+1)*(v(2)+1) + v(0)+v(1)+v(2)
def cmp (a:Vector[Int], b:Vector[Int]) : Boolean = { checksum(a) == checksum(b)}
(1 to 30).foreach (i => {val a=arr; val b=arr; val m = cmp (a, b); println (s"match: $a $b $m") })
match: Vector(0, 1, 2) Vector(0, 1, 0) false
match: Vector(1, 1, 0) Vector(2, 1, 1) false
match: Vector(2, 1, 0) Vector(2, 0, 2) false
match: Vector(0, 0, 2) Vector(0, 1, 1) false
match: Vector(2, 1, 1) Vector(2, 1, 1) true
match: Vector(0, 1, 1) Vector(1, 0, 2) false
match: Vector(2, 0, 2) Vector(2, 0, 0) false
match: Vector(0, 2, 2) Vector(2, 1, 0) false
match: Vector(2, 2, 2) Vector(0, 1, 2) false
match: Vector(2, 2, 0) Vector(1, 1, 0) false
match: Vector(0, 2, 2) Vector(0, 0, 2) false
match: Vector(0, 2, 1) Vector(2, 1, 1) false
match: Vector(0, 2, 1) Vector(1, 0, 0) false
match: Vector(2, 2, 2) Vector(2, 1, 1) false
match: Vector(0, 1, 1) Vector(1, 0, 2) false
match: Vector(1, 0, 0) Vector(1, 0, 2) false
match: Vector(2, 1, 1) Vector(0, 1, 2) false
match: Vector(2, 0, 0) Vector(2, 1, 0) false
match: Vector(1, 2, 1) Vector(2, 1, 2) false
match: Vector(2, 2, 1) Vector(2, 1, 2) true
match: Vector(0, 0, 0) Vector(0, 2, 2) false
match: Vector(2, 0, 1) Vector(0, 1, 1) false
match: Vector(2, 0, 1) Vector(1, 2, 1) false
match: Vector(0, 1, 1) Vector(1, 1, 0) true
match: Vector(0, 2, 0) Vector(1, 0, 0) false
match: Vector(1, 2, 1) Vector(0, 1, 0) false
match: Vector(2, 0, 2) Vector(0, 1, 0) false
match: Vector(0, 1, 0) Vector(1, 2, 2) false
match: Vector(1, 1, 0) Vector(0, 0, 0) false
match: Vector(0, 1, 1) Vector(0, 2, 1) false
还有很多要控制的情况,I&#39;会编写一个检查功能,在比较之前对Vector进行排序。我想,虽然代码是scala,但它易于理解并转换为java等价?
def cmp2 (a:Vector[Int], b:Vector[Int]) : Boolean = { a.sorted == b.sorted}
(1 to 3000).foreach (i => {val a=arr; val b=arr; if (cmp (a, b) != cmp2 (a, b)) println (s"match: $a $b ${cmp(a,b)} ${cmp2(a,b)}") })
// silence
当然,你也可以做一个数学证明:
(a+1)*(b+1)*(c+1)+a+b+c ?= (d+a+1)*(e+b+1)*(c+1)+(d+a)+b+c | d!=0
// or
(a+1)*(b+1)*(c+1)+a+b+c ?= (d+a+1)*(e+b+1)*(c+1)+(d+a)+b+c | d!=0, e!=0
作为读者的练习,像往常一样:)
Random r = new java.util.Random();
int [] arr (int max) {
int[] v = new int[3];
v[0] = r.nextInt (max);
v[1] = r.nextInt (max);
v[2] = r.nextInt (max);
return v;
}
int checksum (int[] v) { return (v[0] +1) * (v[1] +1) * (v[2] +1) + v[0] + v[1] + v[2]; }
boolean cmp (int[] a, int[] b) { return checksum(a) == checksum(b); }
for (int i = 0; i < 30; ++i) {
int [] a = arr (3);
int [] b = arr (3);
boolean m = cmp (a, b);
System.out.printf ("match: %6s %6s %b\n", Arrays.toString (a), Arrays.toString (b), m);
}