如何在时间复杂度方面改进算法?

时间:2016-02-19 21:31:28

标签: java algorithm big-o time-complexity

我正在尝试测量算法的时间复杂度:

public boolean rotateAndCompare(int[] fst, int[] snd) {
    int len = fst.length;
    for (int k = 0; k < len; k++) {
        for (int j = 0; j < len; j++) {
            if (fst[(k + j) % len] != snd[j]) {
                break;
            }
            if (j == len - 1) {
                return true;
            }
        }
    }
    return false;
}

我假设它具有O(n*n)复杂度,因为我们遍历数组然后遍历另一个数组。我对吗?如果是这样,我该如何改进呢?

2 个答案:

答案 0 :(得分:3)

如果我理解正确,您的算法会决定fst.length的第一个snd整数是否等于fst,可能会轮换。它假设snd.length >= fst.length。如果这不是您的意思,请在问题中指明。

但假设这是你的真实含义,你可以使用像KMP这样的字符串匹配算法在O(n)中解决这个问题。换句话说,您需要查看snd是否为fst + fst的子阵列,这是一个经典问题。

以下是Java中的示例实现:

import java.util.Arrays;

public class Main {
    public static class KMP {
        private final int F[];
        private final int[] needle;

        public KMP(int[] needle) {
            this.needle = needle;
            this.F = new int[needle.length + 1];

            F[0] = 0;
            F[1] = 0;
            int i = 1, j = 0;
            while (i < needle.length) {
                if (needle[i] == needle[j])
                    F[++i] = ++j;
                else if (j == 0)
                    F[++i] = 0;
                else
                    j = F[j];
            }
        }

        public int find(int[] haystack) {
            int i = 0, j = 0;
            int n = haystack.length, m = needle.length;

            while (i - j <= n - m) {
                while (j < m) {
                    if (needle[j] == haystack[i]) {
                        i++;
                        j++;
                    } else break;
                }
                if (j == m) return i;
                else if (j == 0) i++;
                j = F[j];
            }
            return -1;
        }
    }

    public static boolean rotateAndCompare(int[] fst, int[] snd) {
        int[] fst2 = new int[fst.length * 2];
        System.arraycopy(fst, 0, fst2, 0, fst.length);
        System.arraycopy(fst, 0, fst2, fst.length, fst.length);

        int[] snd2 = Arrays.copyOf(snd, fst.length);
        return new KMP(snd2).find(fst2) >= 0;
    }

    public static void main(String[] args) {
        System.out.println(rotateAndCompare(new int[]{1, 2, 3}, new int[]{3, 1, 2, 4}));
        System.out.println(rotateAndCompare(new int[]{1, 2, 2}, new int[]{3, 1, 2, 4}));
    }
}

答案 1 :(得分:-6)

O(n * n)通常表示为&#34;顺序为n平方&#34;,O(n ^ 2),您的算法是。但是,由于你绝对没有进行长度检查,它可能完全破坏,这比算法的复杂性更严重。 &#39; SND&#39; (这意味着什么呢?为什么这么简洁?)甚至可能没有&#39; len&#39;元素。此外,您可以通过将终端条件作为循环控制的一部分而不是两次检查来获得一些改进。

崩溃的风险比算法复杂性严重得多。一旦你解决了这个问题,你就可以重构索引以使其更加线性,但我怀疑这是不可能的。如果您的问题存在对称性,您可以利用它们。