Java 在另一个较大的数组中查找数组

Java 在另一个较大的数组中查找数组,java,arrays,Java,Arrays,我最近被要求为一份工作编写3个测试程序。它们将使用核心JavaAPI和我选择的任何测试框架编写。在适当的情况下,应实施单元测试 虽然我没有收到任何反馈,但我想他们不喜欢我的解决方案(否则我会从他们那里听到),所以我决定在这里展示我的程序,并询问这个实现是否被认为是好的,如果不是,为什么 为了避免混淆,我现在只问第一个问题 实现一个查找 在另一个较大的数组中。信息技术 应接受两个数组作为参数 它将返回 第一个数组,其中第二个数组 第一次完全发生。如, findArray([2,3,7,1,20],

我最近被要求为一份工作编写3个测试程序。它们将使用核心JavaAPI和我选择的任何测试框架编写。在适当的情况下,应实施单元测试

虽然我没有收到任何反馈,但我想他们不喜欢我的解决方案(否则我会从他们那里听到),所以我决定在这里展示我的程序,并询问这个实现是否被认为是好的,如果不是,为什么

为了避免混淆,我现在只问第一个问题

实现一个查找 在另一个较大的数组中。信息技术 应接受两个数组作为参数 它将返回 第一个数组,其中第二个数组 第一次完全发生。如, findArray([2,3,7,1,20],[7,1])应该 返回2

我没有试图找到任何现有的解决方案,而是想自己去做

可能的原因: 1.应该是静态的。 2.应该使用行注释而不是块注释。 3.没有先检查空值(我知道,只是发现太迟了)。 4. ?

更新
提出了很多理由,我很难选择一个答案,因为很多答案都有很好的解决方案。正如@aditerich所提到的,我倾向于相信他们希望我展示核心API的知识(他们甚至要求我写一个函数,而不是写一个算法)

我认为获得这份工作的最佳方式是提供尽可能多的解决方案,包括: 1.使用Collections.indexofpublist()方法实现,以显示我了解核心集合API。 2.使用蛮力方法实现,但提供更优雅的解决方案。 3.使用搜索算法实现,例如Boyer Moore。 4.使用System.arraycopy()和Arrays.equal()的组合实现。然而,这并不是性能方面的最佳解决方案,它将显示我对标准数组例程的了解

谢谢大家的回答
更新结束。

以下是我写的:

实际计划:

package com.example.common.utils;

/**
 * This class contains functions for array manipulations.
 * 
 * @author Roman
 *
 */
public class ArrayUtils {

    /**
     * Finds a sub array in a large array
     * 
     * @param largeArray
     * @param subArray
     * @return index of sub array
     */
    public int findArray(int[] largeArray, int[] subArray) {

        /* If any of the arrays is empty then not found */
        if (largeArray.length == 0 || subArray.length == 0) {
            return -1;
        }

        /* If subarray is larger than large array then not found */
        if (subArray.length > largeArray.length) {
            return -1;
        }

        for (int i = 0; i < largeArray.length; i++) {
            /* Check if the next element of large array is the same as the first element of subarray */
            if (largeArray[i] == subArray[0]) {

                boolean subArrayFound = true;
                for (int j = 0; j < subArray.length; j++) {
                    /* If outside of large array or elements not equal then leave the loop */
                    if (largeArray.length <= i+j || subArray[j] != largeArray[i+j]) {
                        subArrayFound = false;
                        break;
                    }
                }

                /* Sub array found - return its index */
                if (subArrayFound) {
                    return i;
                }

            }
        }

        /* Return default value */
        return -1;
    }

}

我建议作出以下改善:

  • 将函数设为静态,这样可以避免创建实例

  • 外环条件可能是
    i好的,从我的头顶开始:

    public int findArray(int[] largeArray, int[] subArray) {
    
        int subArrayLength = subArray.length;
    
        if (subArrayLength == 0) {
            return -1;
        }
    
        int limit = largeArray.length - subArrayLength;
    
        int i=0;
    
        for (int i = 0; i <= limit; i++) {
            boolean subArrayFound = true;
    
            for (int j = 0; j < subArrayLength; j++) {
                if (subArray[j] != largeArray[i+j]) {
                    subArrayFound = false;
                    break;
                }
    
            /* Sub array found - return its index */
            if (subArrayFound) {
                return i;
            }
        }
    
        /* Return default value */
        return -1;
    }
    
  • 是的,应该是静态的

  • 一家抱怨这一点的公司不值得为之工作

  • 是的,但是你会怎么做?返回?或者抛出异常?它将以现有的方式抛出异常

  • 我认为主要的问题是你的代码不是很优雅。内部循环中的检查太多。过多的冗余检查

  • 只是生的,从我的头顶上:

    public int findArray(int[] largeArray, int[] subArray) {
    
        int subArrayLength = subArray.length;
    
        if (subArrayLength == 0) {
            return -1;
        }
    
        int limit = largeArray.length - subArrayLength;
    
        int i=0;
    
        for (int i = 0; i <= limit; i++) {
            boolean subArrayFound = true;
    
            for (int j = 0; j < subArrayLength; j++) {
                if (subArray[j] != largeArray[i+j]) {
                    subArrayFound = false;
                    break;
                }
    
            /* Sub array found - return its index */
            if (subArrayFound) {
                return i;
            }
        }
    
        /* Return default value */
        return -1;
    }
    
    public int findArray(int[]大数组,int[]子数组){
    int subArray length=subArray.length;
    如果(子阵列长度==0){
    返回-1;
    }
    int limit=largeArray.length-子阵列长度;
    int i=0;
    对于(int i=0;i
    int findSubArr(int[]arr,int[]subar)
    {
    int lim=阵列长度-子阵列长度;
    
    对于(int i=0;i在较大的整数数组中查找整数数组,可以使用与在较大的字符串中查找子字符串相同的算法。对于这一点,有许多已知的算法(请参阅)。尤其是Boyer-Moore字符串搜索对于大型数组非常有效。您尝试实现的算法效率不高(Wikipedia称之为“naive”实现)

    关于您的问题:

  • 是的,这样的方法应该是静态的
  • 别在意,这是品味的问题
  • 可以包括null检查,或者您应该在JavaDoc中声明不允许使用null值,或者JavaDoc应该声明,当任一参数为null时,将抛出NullPointerException
  • “仅使用核心Java API”的要求也可能意味着他们想看看您是否会重新发明轮子。因此,除了您自己的实现之外,您可以提供单线解决方案,只是为了安全:

    public static int findArray(Integer[] array, Integer[] subArray)
    {
        return Collections.indexOfSubList(Arrays.asList(array), Arrays.asList(subArray));
    }
    

    指出给出的示例包含无效的数组文本可能是一个好主意,也可能不是一个好主意。

    之前发布的一些经过优化的代码:

    public int findArray(byte[] largeArray, byte[] subArray) {
        if (subArray.length == 0) {
            return -1;
        }
        int limit = largeArray.length - subArray.length;
        next:
        for (int i = 0; i <= limit; i++) {
            for (int j = 0; j < subArray.length; j++) {
                if (subArray[j] != largeArray[i+j]) {
                    continue next;
                }
            }
            /* Sub array found - return its index */
            return i;
        }
        /* Return default value */
        return -1;
    }
    
    public int findArray(字节[]大数组,字节[]子数组){
    if(subArray.length==0){
    返回-1;
    }
    int limit=largeArray.length-subArray.length;
    下一步:
    对于(int i=0;i,这里是字符串的#indexOf:

    /**
     * Code shared by String and StringBuffer to do searches. The
     * source is the character array being searched, and the target
     * is the string being searched for.
     *
     * @param   source       the characters being searched.
     * @param   sourceOffset offset of the source string.
     * @param   sourceCount  count of the source string.
     * @param   target       the characters being searched for.
     * @param   targetOffset offset of the target string.
     * @param   targetCount  count of the target string.
     * @param   fromIndex    the index to begin searching from.
     */
    static int indexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
        if (fromIndex >= sourceCount) {
            return (targetCount == 0 ? sourceCount : -1);
        }
        if (fromIndex < 0) {
            fromIndex = 0;
        }
        if (targetCount == 0) {
            return fromIndex;
        }
    
        char first = target[targetOffset];
        int max = sourceOffset + (sourceCount - targetCount);
    
        for (int i = sourceOffset + fromIndex; i <= max; i++) {
            /* Look for first character. */
            if (source[i] != first) {
                while (++i <= max && source[i] != first);
            }
    
            /* Found first character, now look at the rest of v2 */
            if (i <= max) {
                int j = i + 1;
                int end = j + targetCount - 1;
                for (int k = targetOffset + 1; j < end && source[j]
                        == target[k]; j++, k++);
    
                if (j == end) {
                    /* Found whole string. */
                    return i - sourceOffset;
                }
            }
        }
        return -1;
    }
    
    /**
    *由String和StringBuffer共享以执行搜索的代码
    *源是正在搜索的字符数组,目标是
    *正在搜索的字符串。
    *
    *@param source正在搜索的字符。
    *@param sourceOffset源字符串的偏移量。
    *@param sourceCount源字符串的计数。
    *@param目标是要搜索的字符。
    *@param targetOffset目标字符串的偏移量。
    *@param targetCount目标字符串的计数。
    *@param fromIndex开始搜索的索引。
    */
    静态int indexOf(char[]source,int sourceOffset,int sourceCount,
    char[]目标,int targetOffset,int targetCount,
    int fromIndex){
    if(fromIndex>=sourceCount){
    返回(targetCount==0?sourceCount:-1);
    }
    如果(从索引<0){
    fromIndex=0;
    }
    如果(targetCount==0){
    从索引返回;
    }
    char first=目标[targetOffset];
    int max=sourceOffset+(sourceCount-targetCount);
    
    对于(int i=sourceOffset+fromIndex;i以下是一种使用KMP模式匹配算法的方法。此解决方案采用
    O(n+m)
    。其中
    n=大数组长度
    m=子数组长度
    。有关详细信息,请检查:

    蛮力取
    O(n*m)
    。我刚刚检查了
    集合。indexofpublist
    方法也是
    O(n*m)

    公共静态int子字符串索引(int[]大数组,int[]子数组){
    如果(largeArray.length==0 | | s
    
    public static int findArray(Integer[] array, Integer[] subArray)
    {
        return Collections.indexOfSubList(Arrays.asList(array), Arrays.asList(subArray));
    }
    
    public int findArray(byte[] largeArray, byte[] subArray) {
        if (subArray.length == 0) {
            return -1;
        }
        int limit = largeArray.length - subArray.length;
        next:
        for (int i = 0; i <= limit; i++) {
            for (int j = 0; j < subArray.length; j++) {
                if (subArray[j] != largeArray[i+j]) {
                    continue next;
                }
            }
            /* Sub array found - return its index */
            return i;
        }
        /* Return default value */
        return -1;
    }
    
    /**
     * Code shared by String and StringBuffer to do searches. The
     * source is the character array being searched, and the target
     * is the string being searched for.
     *
     * @param   source       the characters being searched.
     * @param   sourceOffset offset of the source string.
     * @param   sourceCount  count of the source string.
     * @param   target       the characters being searched for.
     * @param   targetOffset offset of the target string.
     * @param   targetCount  count of the target string.
     * @param   fromIndex    the index to begin searching from.
     */
    static int indexOf(char[] source, int sourceOffset, int sourceCount,
            char[] target, int targetOffset, int targetCount,
            int fromIndex) {
        if (fromIndex >= sourceCount) {
            return (targetCount == 0 ? sourceCount : -1);
        }
        if (fromIndex < 0) {
            fromIndex = 0;
        }
        if (targetCount == 0) {
            return fromIndex;
        }
    
        char first = target[targetOffset];
        int max = sourceOffset + (sourceCount - targetCount);
    
        for (int i = sourceOffset + fromIndex; i <= max; i++) {
            /* Look for first character. */
            if (source[i] != first) {
                while (++i <= max && source[i] != first);
            }
    
            /* Found first character, now look at the rest of v2 */
            if (i <= max) {
                int j = i + 1;
                int end = j + targetCount - 1;
                for (int k = targetOffset + 1; j < end && source[j]
                        == target[k]; j++, k++);
    
                if (j == end) {
                    /* Found whole string. */
                    return i - sourceOffset;
                }
            }
        }
        return -1;
    }
    
    public static int subStringIndex(int[] largeArray, int[] subArray) {
        if (largeArray.length == 0 || subArray.length == 0){
          throw new IllegalArgumentException();
    }
        if (subArray.length > largeArray.length){
          throw new IllegalArgumentException();
    }
    
        int[] prefixArr = getPrefixArr(subArray);
        int indexToReturn = -1;
    
        for (int m = 0, s = 0; m < largeArray.length; m++) {
          if (subArray[s] == largeArray[m]) {
            s++;
          } else {
            if (s != 0) {
              s = prefixArr[s - 1];
              m--;
            }
          }
          if (s == subArray.length) {
            indexToReturn = m - subArray.length + 1;
            break;
          }
        }
    
        return indexToReturn;
      }
    
      private static int[] getPrefixArr(int[] subArray) {
        int[] prefixArr = new int[subArray.length];
        prefixArr[0] = 0;
    
        for (int i = 1, j = 0; i < prefixArr.length; i++) {
          while (subArray[i] != subArray[j]) {
            if (j == 0) {
              break;
            }
            j = prefixArr[j - 1];
          }
    
          if (subArray[i] == subArray[j]) {
            prefixArr[i] = j + 1;
            j++;
          } else {
            prefixArr[i] = j;
          }
    
        }
        return prefixArr;
      }
    
    Clean and improved code 
    
    public static int findArrayIndex(int[] subArray, int[] parentArray) {
        if(subArray.length==0){
            return -1;
        }
        int sL = subArray.length;
        int l = parentArray.length - subArray.length;
        int k = 0;
        for (int i = 0; i < l; i++) {
            if (parentArray[i] == subArray[k]) {
                for (int j = 0; j < subArray.length; j++) {
                    if (parentArray[i + j] == subArray[j]) {
                        sL--;
                        if (sL == 0) {
                            return i;
                        }
    
                    }
    
                }
            }
    
        }
        return -1;
    }
    
    public final class ArrayUtils {
        // main method
    
        public static int indexOf(int[] haystack, int[] needle) {
            return indexOf(haystack, needle, 0);
        }
    
        // helper methods
    
        private static int indexOf(int[] haystack, int[] needle, int fromIndex) {
            for (int i = fromIndex; i < haystack.length - needle.length; i++) {
                if (containsAt(haystack, needle, i)) {
                    return i;
                }
            }
            return -1;
        }
    
        private static boolean containsAt(int[] haystack, int[] needle, int offset) {
            for (int i = 0; i < needle.length; i++) {
                if (haystack[i + offset] != needle[i]) {
                    return false;
                }
            }
            return true;
        }
    
        // prevent initialization
    
        private ArrayUtils() {}
    }
    
        byte[] arr1 = {1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 1, 3, 4, 56, 6, 7};
        byte[] arr2 = {9, 1, 3};
    
        boolean i = IsContainsSubArray(arr1, arr2);
    
     public static boolean IsContainsSubArray(byte[] Large_Array, byte[] Sub_Array){
        try {
            int Large_Array_size, Sub_Array_size, k = 0;
    
            Large_Array_size = Large_Array.length;
            Sub_Array_size = Sub_Array.length;
    
            if (Sub_Array_size > Large_Array_size) {
                return false;
            }
            for (int i = 0; i < Large_Array_size; i++) {
                if (Large_Array[i] == Sub_Array[k]) {
                    k++;
                } else {
                    k = 0;
                }
                if (k == Sub_Array_size) {
                    return true;
                }
            }
        } catch (Exception e) {
        }
        return false;
    }
    
    import javax.annotation.Nullable;
    
    /**
     * Ensures that an object reference passed as a parameter to the calling method is not null.
     *
     * @param reference an object reference
     * @param errorMessage the exception message to use if the check fails; will be converted to a
     *     string using {@link String#valueOf(Object)}
     * @return the non-null reference that was validated
     * @throws NullPointerException if {@code reference} is null
     */
    public static <T> T checkNotNull(T reference, @Nullable Object errorMessage) {
        if (reference == null) {
            throw new NullPointerException(String.valueOf(errorMessage));
        }
        return reference;
    }
    
    
    /**
     * Returns the start position of the first occurrence of the specified {@code
     * target} within {@code array}, or {@code -1} if there is no such occurrence.
     *
     * <p>More formally, returns the lowest index {@code i} such that {@code
     * java.util.Arrays.copyOfRange(array, i, i + target.length)} contains exactly
     * the same elements as {@code target}.
     *
     * @param array the array to search for the sequence {@code target}
     * @param target the array to search for as a sub-sequence of {@code array}
     */
    public static int indexOf(int[] array, int[] target) {
        checkNotNull(array, "array");
        checkNotNull(target, "target");
        if (target.length == 0) {
            return 0;
        }
    
        outer:
        for (int i = 0; i < array.length - target.length + 1; i++) {
            for (int j = 0; j < target.length; j++) {
                if (array[i + j] != target[j]) {
                    continue outer;
                }
            }
            return i;
        }
        return -1;
    }
    
    public static void findArray(int[] array, int[] subArray) {
    
            if (subArray.length > array.length) {
                return;
            }
    
            if (array == null || subArray == null) {
                return;
            }
    
            if (array.length == 0 || subArray.length == 0) {
                return;
            }
    
            //Solution 1
            List<Integer> master = Arrays.stream(array).boxed().collect(Collectors.toList());
            List<Integer> pattern = IntStream.of(subArray).boxed().collect(Collectors.toList());
    
            System.out.println(Collections.indexOfSubList(master, pattern));
    
            //Solution2
            for (int i = 0; i <= array.length - subArray.length; i++) {
                String s = Arrays.toString(Arrays.copyOfRange(array, i, i + subArray.length));
    
                if (s.equals(Arrays.toString(subArray))) {
                    System.out.println("Found at:" + i);
                    return;
                }
            }
            System.out.println("Not found.");
        }
    
    String[] smallArray = {"1","2","3"};
    final String[] bigArray = {"0","1","2","3","4"};
    boolean result = Arrays.stream(smallArray).allMatch(s -> Arrays.stream(bigArray).anyMatch(b -> b.equals(s)));