Java 对于N个大小相等且整数升序的数组,如何选择数组的公共数字?
今天在一次采访中,我被问到一个算法问题,我很想得到各位成员的意见。问题如下: 给定大小相同且整数升序为整数的N个数组,如何选择所有N个数组的公共数字 起初,我的想法是迭代元素,从第一个数组开始,一直到数组的其余部分。但如果我是对的,那将导致N次N次迭代。因此,我想出了一个解决方案,通过将元素作为键,值作为计数器,将计数添加到映射中。这样,我相信时间复杂度仅为N。下面是我的方法在Java中的实现Java 对于N个大小相等且整数升序的数组,如何选择数组的公共数字?,java,algorithm,Java,Algorithm,今天在一次采访中,我被问到一个算法问题,我很想得到各位成员的意见。问题如下: 给定大小相同且整数升序为整数的N个数组,如何选择所有N个数组的公共数字 起初,我的想法是迭代元素,从第一个数组开始,一直到数组的其余部分。但如果我是对的,那将导致N次N次迭代。因此,我想出了一个解决方案,通过将元素作为键,值作为计数器,将计数添加到映射中。这样,我相信时间复杂度仅为N。下面是我的方法在Java中的实现 public static void main(String[] args) { int[]
public static void main(String[] args) {
int[] arr1 = { 1, 4, 6, 8,11,15 };
int[] arr2 = { 3, 4, 6, 9, 10,16 };
int[] arr3 = { 1, 4, 6, 13,15,16 };
System.out.println(commonNumbers(arr1, arr2, arr3));
}
public static List<Integer> commonNumbers(int[] arr1, int[] arr2, int[] arr3) {
Map<Integer, Integer>countMap = new HashMap<Integer, Integer>();
for(int element:arr1)
{
countMap.put(element, 1);
}
for(int element:arr2)
{
if(countMap.containsKey(element))
{
countMap.put(element,countMap.get(element)+1);
}
}
for(int element:arr3)
{
if(countMap.containsKey(element))
{
countMap.put(element,countMap.get(element)+1);
}
}
List<Integer>toReturn = new LinkedList<Integer>();
for(int key:countMap.keySet())
{
int count = countMap.get(key);
if(count==3)toReturn.add(key);
}
return toReturn;
}
publicstaticvoidmain(字符串[]args){
int[]arr1={1,4,6,8,11,15};
int[]arr2={3,4,6,9,10,16};
int[]arr3={1,4,6,13,15,16};
System.out.println(公共编号(arr1、arr2、arr3));
}
公共静态列表CommonNumber(int[]arr1、int[]arr2、int[]arr3){
MapcountMap=新HashMap();
for(int元素:arr1)
{
countMap.put(元素,1);
}
for(int元素:arr2)
{
if(countMap.containsKey(元素))
{
countMap.put(元素,countMap.get(元素)+1);
}
}
for(int元素:arr3)
{
if(countMap.containsKey(元素))
{
countMap.put(元素,countMap.get(元素)+1);
}
}
ListtoReturn=新建LinkedList();
for(int键:countMap.keySet())
{
int count=countMap.get(键);
如果(计数==3)返回。添加(键);
}
回归回归;
}
我只是对三个阵列进行了测试,以了解它将如何工作。虽然我认为这仍然适用,但问题讨论的是N数组
我的问题是,考虑到时间复杂性,有没有更好的方法来解决这个问题?将其视为3个队列。值不同时,“remove”(通过增加数组索引)最小。当它们匹配时,“删除”(并记录)匹配
int i1 = 0;
int i2 = 0;
int i3 = 0;
while (i1 < array1.size && i2 < array2.size && i3 < array3.size) {
int next1 = array1[i1];
int next2 = array2[i2];
int next3 = array3[i3];
if (next1 == next2 && next1 == next3) {
recordMatch(next1);
i1++;
i2++;
i3++;
}
else if (next1 < next2 && next1 < next3) {
i1++;
}
else if (next2 < next1 && next2 < next3) {
i2++;
}
else {
i3++;
}
}
inti1=0;
int i2=0;
int i3=0;
而(i1
很容易推广到N个数组,但是对于N个较大的数组,您可能希望以某种方式优化比较(NPE的“堆”)。我认为这可以通过对N个数组和N个元素进行单个并行迭代来解决。在堆中,您将保留N个输入数组中每个数组的当前元素 其思想是,在每一步中,您都要沿着元素位于堆顶部(即最小)的数组前进 您需要能够检测堆何时由完全相同的值组成。只要跟踪添加到堆中的最大元素,这可以在固定时间内完成
如果每个数组包含M个元素,最坏情况下的时间复杂度将是
O(M*N*log(N))
,它需要O(N)
内存。好的-这里可能有点幼稚,但我认为线索是数组是按升序排列的。我的java已经生锈了,但这里有一些psedoocode。我还没有测试过它,所以它可能并不完美,但它应该是一种快速的方法:
I = 1
J = 1
K = 1
While I <= Array1Count and J <= Array2Count and K <= Array3Count
If Array1(I) = Array2(J)
If Array1(I) = Array3(K)
=== Found Match
I++
J++
K++
else
if Array1(I) < Array3(K)
I++
end if
end if
else
If Array1(I) < Array2(J)
I++
else
if Array2(J) < Array3(K)
J++
else
K++
end if
end if
end if
Wend
I=1
J=1
K=1
我认为另一种方法与我们在Mergesort中所做的类似:同时遍历所有数组,得到相同的数字。这将利用数组是按排序顺序排列的这一事实,并且除了输出数组之外不会使用额外的空间。如果只需要打印常用数字,则不需要额外的空间
public static List<Integer> commonNumbers(int[] arrA, int[] arrB, int[] arrC) {
int[] idx = {0, 0, 0};
while (idxA<arrA.length && idxB<arrB.length && idxC<arrC.length) {
if ( arrA[idx[0]]==arrB[idx[1]] && arrB[idx[1]]==arrC[idx[2]] ) {
// Same number
System.out.print("Common number %d\n", arrA[idx[0]]);
for (int i=0;i<3;i++)
idx[i]++;
} else {
// Increase the index of the lowest number
int idxLowest = 0; int nLowest = arrA[idx[0]];
if (arrB[idx[1]] < nLowest) {
idxLowest = 1;
nLowest = arrB[idx[1]];
}
if (arrC[idx[2]] < nLowest) {
idxLowest = 2;
}
idx[idxLowest]++;
}
}
}
公共静态列表公共编号(int[]arrA,int[]arrB,int[]arrC){
int[]idx={0,0,0};
而(idxAtry
公共静态集合commonNumber(int[]arr1、int[]arr2、int[]arr3){
Set s1=createSet(arr1);
Set s2=创建集(arr2);
Set s3=创建集(arr3);
s1.保留(s2);
s1.保留(s3);
返回s1;
}
私有静态集createSet(int[]arr){
Set s=新的HashSet();
对于(内部e:arr){
s、 加(e);
}
返回s;
}
这是我在算法类中学习的方法。不确定它是否“更好”,但它使用更少的内存和开销,因为它直接遍历数组,而不是首先构建映射
public static List<Integer> commonNumbers(int[] arr1, int[] arr2, int[] arr3, ... , int[] arrN) {
List<Integer>toReturn = new LinkedList<Integer>();
int len = arr1.length;
int j = 0, k = 0, ... , counterN = 0;
for (int i = 0; i < len; i++) {
while (arr2[j] < arr1[i] && j < len) j++;
while (arr3[k] < arr1[i] && k < len) k++;
...
while (arrN[counterN] < arr1[i] && counterN < len) counterN++;
if (arr1[i] == arr2[j] && arr2[j] == arr3[k] && ... && arr1[i] == arrN[counterN]) {
toReturn.add(arr1[i]);
}
}
return toReturn;
}
公共静态列表公共编号(int[]arr1,int[]arr2,int[]arr3,…,int[]arrN){
ListtoReturn=新建LinkedList();
int len=arr1.1长度;
int j=0,k=0,…,计数器n=0;
对于(int i=0;i
您的解决方案是可以接受的,但它使用NxM空间。您可以使用O(N)空间(其中N是数组的数量)或O(1)空间
解决方案#1(Luigi Mendoza)
假设有许多小数组(M,这可以在O(M*N)
中解决,M是数组的长度
让我们看看N=2
会发生什么,这将是一个排序列表交集问题,在O(l1+l2)
时间内运行一个经典的类似合并的解决方案。(l1=第一个数组的长度,l2=第二个数组的长度)。(了解更多信息。)
现在,让我们在一个归纳m中重新迭代算法N次
public static List<Integer> commonNumbers(int[] arr1, int[] arr2, int[] arr3, ... , int[] arrN) {
List<Integer>toReturn = new LinkedList<Integer>();
int len = arr1.length;
int j = 0, k = 0, ... , counterN = 0;
for (int i = 0; i < len; i++) {
while (arr2[j] < arr1[i] && j < len) j++;
while (arr3[k] < arr1[i] && k < len) k++;
...
while (arrN[counterN] < arr1[i] && counterN < len) counterN++;
if (arr1[i] == arr2[j] && arr2[j] == arr3[k] && ... && arr1[i] == arrN[counterN]) {
toReturn.add(arr1[i]);
}
}
return toReturn;
}
public static List<Integer> getCommon(List<List<Integer>> list){
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
int c=0;
for (List<Integer> is : list) {
c++;
for (int i : is) {
if(map.containsKey(i)){
map.put(i, map.get(i)+1);
}else{
map.put(i, 1);
}
}
}
List<Integer>toReturn = new LinkedList<Integer>();
for(int key:map.keySet())
{
int count = map.get(key);
if(count==c)toReturn.add(key);
}
return toReturn;
}