Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I determine if an array contains all the integers in a separate array

I'm in my schools ap computer science class and I'm stuck on this one problem. and cant really even really come up with an idea on how to solve it.

Here it is word for word: Write a static method named contains that accepts two arrays of integers a1 and a2 as parameters and that returns a boolean value indicating whether or not a2's sequence of elements appears in a1 (true for yes, false for no). The sequence of elements in a2 may appear anywhere in a1 but must appear consecutively and in the same order. For example, if variables called list1 and list2 store the following values:

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

Then the call of contains(list1, list2) should return true because list2's sequence of values {1, 2, 1} is contained in list1 starting at index 5. If list2 had stored the values {2, 1, 2}, the call of contains(list1, list2) would return false because list1 does not contain that sequence of values. Any two lists with identical elements are considered to contain each other, so a call such as contains(list1, list1) should return true.

You may assume that both arrays passed to your method will have lengths of at least 1. You may not use any Strings to help you solve this problem, nor methods that produce Strings such as Arrays.toString.

If someone could point me in the right direction that would be great.

also here's one attempt i came up with but it doesn't have a sufficient number of tests

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;
}
like image 680
BenDeV Avatar asked Jan 30 '14 20:01

BenDeV


3 Answers

Here's a recursive way to do this:

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);
    }

}

Each time we fail to find the matching sequence, we create a subset of the array, excluding the first element, and pass that back to contains to continue the checks.Here is an output of each iteration:

First time: set1 = [1, 6, 2, 1, 4, 1, 2, 1, 8] and set2 = [1, 2, 1] No match is found at the beginning of the array (we break out when comparing 6 and 2. The next recursive call is this:

set1= [6, 2, 1, 4, 1, 2, 1, 8], [1, 2, 1]

the next recursion compares [2, 1, 4, 1, 2, 1, 8] [1, 2, 1]

and so on until the final recursion compares: [1, 2, 1, 8] [1, 2, 1] and finds the match in order.

like image 85
Joel Avatar answered Sep 28 '22 05:09

Joel


For consecutive

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;
}

To avoid a label you can use a method which might be clearer

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;
}

If it only needs to be in order

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;
}
like image 29
Peter Lawrey Avatar answered Sep 28 '22 05:09

Peter Lawrey


I would say that as far as the mentality, you should think "work the first element against the array until a match".

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;

In this sense, you will only advance as far down your second array for comparison as needed. If, after going through all the elements in set2, you end up with the same length, then it's contained within set1. And of course, ask if you have questions :)

like image 36
Rogue Avatar answered Sep 28 '22 07:09

Rogue