如何确定数组是不是包含单独数组中的所有整数

Posted

技术标签:

【中文标题】如何确定数组是不是包含单独数组中的所有整数【英文标题】:How do I determine if an array contains all the integers in a separate array如何确定数组是否包含单独数组中的所有整数 【发布时间】:2014-02-23 08:55:20 【问题描述】:

我在我学校的计算机科学课上,我被困在这个问题上。甚至真的想不出如何解决它的想法。

这里是逐字逐句: 编写一个名为 contains 的静态方法,它接受两个整数数组 a1 和 a2 作为参数,并返回一个布尔值,指示 a2 的元素序列是否出现在 a1 中(true 表示是,false 表示否)。 a2 中的元素序列可以出现在 a1 中的任何位置,但必须以相同的顺序连续出现。例如,如果名为 list1 和 list2 的变量存储以下值:

int[] list1 = 1, 6, 2, 1, 4, 1, 2, 1, 8;
int[] list2 = 1, 2, 1;

那么contains(list1, list2) 的调用应该返回true,因为list2 的值序列1, 2, 1 包含在list1 中从索引5 开始。如果list2 存储了值2, 1, 2,则contains(list1, list2) 的调用将返回false,因为list1 不包含该值序列。任何两个具有相同元素的列表都被认为是相互包含的,所以像contains(list1, list1) 这样的调用应该返回true。

您可以假设传递给您的方法的两个数组的长度都至少为 1。您不能使用任何字符串来帮助您解决这个问题,也不能使用产生字符串的方法,例如 Arrays.toString。

如果有人能指出我正确的方向,那就太好了。

这也是我想出的一种尝试,但它没有足够数量的测试

public static boolean contains(int[] set1, int[] set2) 
    boolean contains = false;
    for (int i = 0; i < set1.length; i++) 
        for (int a = 0; a < set2.length - 1; a++) 
            if (set1[i] == set2[a] && set1[i + 1] == set2[a + 1]) 
                contains = true;
             else 
                contains = false;
            
        
    
    return contains;

【问题讨论】:

在第一个循环中,注意越界,i &lt; set1.length - set2.length,因为你匹配的是 set1[i+1],如果 i 是最后一个索引,你的程序会崩溃。否则你基本上是在正确的轨道上。 您需要一个循环来尝试将一个数组与另一个数组进行比较。当您找到匹配项时,您会寻找下一个值。如果到达第二个数组的末尾,则匹配,如果到达第一个数组的末尾,则失败。 【参考方案1】:

int first=list2[0]; 开头,然后在list1 中找到该号码。接下来,遍历list2 中的所有值,同时从先前找到的位置循环遍历list1,直到验证整个list2 存在于list1 中或发现差异。如果发现差异,请在先前找到的位置后使用first 重新启动。

通过调整无耻地复制另一个答案:

public static boolean contains(int[] set1, int[] set2) 
    for (int i = 0, j = 0; i < set1.length; i++) 
        if (set1[i] == set2[j]) 
            if (++j >= set2.length)
                return true;
        
        else 
            i -= j;
            j = 0;
        
    
    return false;

这种连续版本机制还确保在没有任何额外检查的情况下不会发生溢出。

【讨论】:

【参考方案2】:

连续

public static boolean contains(int[] set1, int[] set2) 
     OUTER:
     for (int i = 0; i < set1.length - set2.length; i++) 
         for (int j = 0; j < set2.length; j++) 
             if (set1[i + j] != set2[j])
                  continue OUTER;
         
         return true;
      
     return false;


为了避免标签,您可以使用可能更清晰的方法

public static boolean contains(int[] set1, int[] set2) 
     for (int i = 0; i < set1.length - set2.length; i++)
         if (!matches(set1, i, set2))
             return false;
     return true;


public static boolean matches(int[] set1, int off, int[] set2) 
     for (int j = 0; j < set2.length; j++)
         if (set1[off + j] != set2[j])
               return false;
     return true;


如果它只需要有序

public static boolean contains(int[] set1, int[] set2) 
     for (int i = 0, j = 0; i < set1.length; i++)
         if (set1[i] == set2[j]) 
             if (++j >= set2.length)
                 return true;
     return false;

【讨论】:

@crush 同意,这就是为什么连续检查更好。 一个不错的标签用例哈。 只是想知道,使用标签仍然被认为是好的吗?我一直都知道 java 对 goto 没有真正的支持(除了保留关键字),但在双循环中,我最终使用特定的中断变量来做到这一点。 @abiessu 是的, 应该放在 return false; 之前 @TwoThe 你甚至可以向我们展示它是如何在没有标签的情况下完成的。【参考方案3】:

我想说,就心态而言,您应该考虑“将第一个元素与数组匹配,直到匹配”。

public static boolean contains(int[] set1, int[] set2) 
    for (int i = 0; i < set1.length; i++) 
       int count = 0;
       for (int w = 0; w < set2.length; w++) 
          if (set2[w] == set1[i + w]) 
              count++;
           else 
              count = 0;
              continue;
          
       
       if (count == set2.length) 
           return true;
       
    
    return false;

从这个意义上说,您只会根据需要向前推进第二个数组以进行比较。如果在遍历set2 中的所有元素之后,您最终得到相同的长度,那么它包含在set1 中。当然,如果您有任何问题,请询问:)

【讨论】:

【参考方案4】:

Demo of this answer at IDEOne.com

我想出了以下功能。阅读 cmets 以了解其背后的逻辑:

public static boolean contains(int[] a, int[] b) 
    //Loop until there aren't enough elements left in a to match b.
    for (int i = 0; i < a.length - b.length + 1; i++) 
        for (int j = 0; j < b.length; j++) 

            //If the jth element of b doesn't match
            //the corresponding element of a, then move
            //to the next step in the sequence.
            if (a[i + j] != b[j])
                break;

            //If we are at the end of the loop, return
            //true because that means we found a consecutive match.
            if (j == b.length - 1)
                return true;

        
    

    return false; //If we got here, there are no matches.

【讨论】:

Err... 在1 1 1 1 1 1 1 中查找1 2 1 会在内部循环中导致此错误... @abiessu 我可以检查i &lt; a.length - b.length + 1;【参考方案5】:

这是一种递归方式:

public static boolean contains(int[] set1, int[] set2) 
    //System.out.println(Arrays.toString(set1) + " " + Arrays.toString(set2));

    //set 2 cannot be contained within set 1 because there aren't 
    //enough elements. This either means that we recursed too deep
    //within the first set that there are not enough elements, or
    //there were not enough elements to begin with.
    if (set1.length < set2.length) return false;

    //from the start of each set, count the number of matches in order
    int numMatched = 0;
    while (numMatched < set2.length && set1[numMatched] == set2[numMatched]) 
        numMatched++;
    

    if (numMatched == set2.length) 
        //the number of matches found equals the length of the set to
        //search for, so we have found a match. Return true to unravel
        //the recursion.
        return true;
    else 
        //we didn't find a match, so shift the array by 1 and then
        //recursively call this function to compare again.
        int[] subset = Arrays.copyOfRange(set1,  1,  set1.length);
        return contains(subset, set2);
    


每次找不到匹配序列时,我们都会创建数组的一个子集,不包括第一个元素,并将其传递回 contains 以继续检查。以下是每次迭代的输出:

第一次:set1 = [1, 6, 2, 1, 4, 1, 2, 1, 8] 和 set2 = [1, 2, 1] 在数组的开头没有找到匹配项(我们在比较 6 和 2 时爆发。下一个递归调用是这样的:

设置1= [6, 2, 1, 4, 1, 2, 1, 8], [1, 2, 1]

下一次递归比较 [2, 1, 4, 1, 2, 1, 8] [1, 2, 1]

以此类推,直到最后的递归比较: [1, 2, 1, 8] [1, 2, 1] 并按顺序找到匹配项。

【讨论】:

非常感谢,使用 while 循环比尝试测试单个值更有意义。 虽然这是一个有趣的解决方案,但会发生很多不必要的内存复制。 @TwoThe 内存复制很多,对于大集合肯定会出问题。在 C++ 中,我可能会使用指针算术或可选输入变量作为偏移量或函数内的静态变量。这些在 Java 中不可用,并且分配没有提到其他变量。没有创建两个函数,一个有 2 个输入,一个有 3 个输入,或者在这个函数中定义一个做同样事情的类,如何改变它以避免数组复制并仍然保持递归? 除了我下面的回答,还有一个问题:C++ 的*(pArray + index) 和Java 的array[index] 有什么区别? 在 C++ 中,我可以接受一个指针作为输入参数,然后当我递归调用该函数时,我可以传入一个指向地址 pArray + 1 的元素的指针,而不是复制数组。当然,使用指针会导致确定实际数组长度的其他问题,但这是一个不同的问题,我可能会使用静态函数变量来避免它。您使用的方法是非递归的,但由于有很多这样的解决方案,我想说明另一种可能性。【参考方案6】:

我想了想,想出了这个解决方案:

static boolean contains(final int[] list1, final int[] list2) 
  final int limit = list1.length - list2.length + 1; // we do not need to check an index >= limit, because list2 wouldn't fit anymore at this point

  for (int indexL1 = 0, indexL2 = 0; indexL1 < limit; ++indexL1) 
    while (list1[indexL1 + indexL2] == list2[indexL2])  // check all matches from here
      ++indexL2;
      if (indexL2 == list2.length)  // if all of list2 matched so far, we found it
        return true;
      
    
    indexL2 = 0; // we did not find it, start from beginning of list2 again
  

  return false; // no match found

我称之为 Lawrey-Solution。

【讨论】:

+1 寻求答案。您确定这是最简单的解决方案吗? 所有这些复杂性真的比不使用标签更好吗? 一个 for 循环 + 一个 while 循环,不确定这是否过于复杂。如果这是我不知道的最简单/最快的方法,但它可以在没有标签、内存副本或其他花哨的东西的情况下工作。

以上是关于如何确定数组是不是包含单独数组中的所有整数的主要内容,如果未能解决你的问题,请参考以下文章

php编程:如何确定数组中的元素是不是包含某一字符串?

如何检查整数0是不是包含在数组中无痛,ElasticSearch

无法确定字符串是不是包含数组中的单词

如何根据数组是不是包含pymongo中的特定元素来更新所有文档?

确定字符串是不是是Java中的整数[重复]

如何检查字节数组是不是包含 Java 中的 Unicode 字符串?