在下面的Java代码中,有什么方法可以使执行速度更快?

时间:2019-01-23 06:23:06

标签: java performance optimization coding-efficiency

我的Java代码如下。

boolean almostIncreasingSequence(int[] sequence) {

        Integer[] arr = new Integer[sequence.length];

        for(int ctr = 0; ctr < sequence.length; ctr++) {
            arr[ctr] = Integer.valueOf(sequence[ctr]); // returns Integer value
        }
        System.out.println("Integer :: " + arr);
        List<Integer> al = new ArrayList<Integer>(); 

        // adding elements of array to arrayList. 
        Collections.addAll(al, arr);
        System.out.println("list :: " + al);
        int save, flag = 0;
        for(int i=0; i<al.size(); i++) {
            save = al.get(i);
            al.remove(i);
            if(al.size()==1) return true;
            for(int j=0; j<al.size()-1; j++) {
                if(al.get(j+1) > al.get(j)) {
                    flag = 0;
                    continue;
                }
                else {
                    flag = 1;
                    break;
                }
            }
                if(flag == 0) {
                    return true;
                }
                al.add(i,save);
            }

        if(flag == 1)
            return false;
        return true;
    }

该代码用于问题“将整数序列作为数组,确定是否可以通过从数组中删除不超过一个元素来确定严格递增的序列。”

对于某些测试用例,它表明执行此操作需要3秒钟以上的时间。但是,我不确定在哪里可以进行更改以更快地执行它。我没有测试用例。

在这里,我创建了2个for循环,因为在第一个循环中,我生成了要删除每个索引的列表,在第二个循环中,我遍历了删除了元素的新列表。

like样本数组是{1,2,4,3},然后在第一个循环中,我将创建一个数组,该数组将是{2,4,3},{1,4,3},{1,2 ,3}和{1,2,4}。在第二个循环中,我遍历所有这四个数组以比较每个元素。

4 个答案:

答案 0 :(得分:4)

主要观察结果是该列表可以分解为3个部分(可能为空):

list = list[0..s) + list[s..e) + list[e..length)

list[0..s)list[e..length)是严格递增的列表,而list[s..e)是介于两者之间的内容。

由于您知道这些前缀和后缀列表严格增加,因此您无需在这些列表中重复检查此属性。

您可以选择se的任何值,但要遵守约束0 <= s <= e < length,但是假设您选择的值应尽可能大s,并且e尽可能小。

如果列表具有所需的总体属性,则可以:

  • s == length,因此该列表已经严格增加而没有删除任何内容。
  • list[s..e)的长度最大为1(e-s == 1),并且list[0..s) + list[e..length)严格增加。您可以通过简单比较list[s-1] < list[e]来进行检查。
  • list[s..e)为空(s == e),因此您需要list[0..s-1) + list [e..length)(即删除前缀的最后一个元素)或list[0..s) + list[e+1..length)(即删除第一个元素)后缀)严格增加。分别选中(s == 0 || list[s-1] < list[e])(e+1 == length || list[s] < list[e+1])
  • 如果list[s..e)具有多个元素(e-s > 1),则需要删除多个元素以赋予列表所需的属性。

要找到se

从零开始的整数指针s开始。将其递增,直到到达末尾或指向某个元素,使得list[0..s)是严格增加的列表,而list[0..s+1)则不是。

以列表长度的整数指针e开始。减少它,而e>slist[e-1..length)并不是严格增加的列表。

答案 1 :(得分:-1)

您的代码包含2个嵌套的for循环,这两个循环都遍历整个列表。这意味着,如果您的列表中有100000个项目,那么在最坏的情况下,代码将需要100000 * 100000步。当然,这很慢。

由于列表始终是“几乎已排序”的,因此您可能无需检查列表的开头,因为您已经知道列表已排序。直观地看一下最后几个列表项就足够了,记住该列表包含多少对未排序的对。

答案 2 :(得分:-1)

更新2: 也尝试此代码 (最多2个循环) 可能进行进一步优化,但仍会产生O(n)时间

public class TstList {

public static boolean compute(int a[]) {
    if (compute_1(a))
        return true;
    return compute_2(a);
}

public static boolean compute_1(int a[]) {
    if (a.length < 2)
        return true;
    int previous = a[0];
    int counter = 0;
    for (int i = 1; i < a.length; i++) {

        if (previous < a[i]) {
            previous = a[i];
            continue;
        } else {
            if (i == 1)
                previous = a[i];
            else
                previous = a[i - 1];

            counter++;
        }

        if (counter > 1)
            return false;
    }
    return true;
}

public static boolean compute_2(int a[]) {
    if (a.length < 2)
        return true;
    int previous = a[0];
    int counter = 0;
    for (int i = 1; i < a.length; i++) {

        if (previous < a[i]) {
            previous = a[i];
            continue;
        } else {
            previous = a[i];
            counter++;
        }

        if (counter > 1)
            return false;
    }
    return true;
}
public static void main(String arg[]) {

    System.out.println(compute(new int[] { 1, 2, 3, 4, 6 }));       \\1
    System.out.println(compute(new int[] { 1, 2, 3, 1, 4, 6 }));    \\2
    System.out.println(compute(new int[] { 1, 2, 1, 3, 1, 4, 6 })); \\3
    System.out.println(compute(new int[] { 1, 2, 3, 4, 6, 3 }));    \\4
    System.out.println(compute(new int[] { 3, 2, 1 }));             \\5
    System.out.println(compute(new int[] { 10, 1, 2, 3, 4, 5 }));   \\6
    System.out.println(compute(new int[] { 1, 2, 5, 3, 5 }));       \\7

}
}

输出

true  \\1
true  \\2
false \\3
true  \\4
false \\5 
true  \\6
true  \\7

答案 3 :(得分:-1)

我会同意的。

编辑:提供了更新的解决方案。它很快,但可读性不好。 我还包括一个main()类以及一些我测试了此代码的标准序列。 (采用一种易于测试人员验证的格式,可以添加任何额外的案例)。

/**
 * Returns true if by removing maximum 1-entry the sequence can be strictly increasing.If not, it returns false. Doesn't check
 * if sequence is empty
 */
private static boolean checkIfRemovingMaxOneElementItIsStrictlyIncreasing(final int[] sequence)
{
    boolean isFirstNonDecreasingSequence = true;
    final int length = sequence.length;
    int maxValue = sequence[0];
    for (int i = 1; i < length; i++)
    {
        if (sequence[i] <= maxValue)
        {
            if (isFirstNonDecreasingSequence == true)
            {
                if ((i + 1) < length) // check this is not the last element
                {
                    if ((sequence[i - 1] >= sequence[i + 1])) // Check if it is peak or pit
                    {
                        // [i-1] is a local peak. Remove [i-1]
                        if (i > 1)
                        {
                            if (sequence[i] <= sequence[i - 2])
                            {
                                return false;
                            }
                        }
                        maxValue = sequence[i];
                    }
                    // else { // [i] is a local pit. Remove [i]. maxValue is not updated. }
                    isFirstNonDecreasingSequence = false;
                }
            }
            else
            {
                return false;
            }
        }
        else
        {
            maxValue = sequence[i];
        }
    }
    return true;
}

public static void main(final String[] args)
{
    final List<int[]> testInputs = new ArrayList<>();
    final List<Boolean> correctResults = new ArrayList<>();
    final List<Boolean> results = new ArrayList<>();

    testInputs.add(new int[] { 0 }); // single-element sequence
    correctResults.add(true);

    testInputs.add(new int[] { 0, 0 }); // two-element sequence
    correctResults.add(true);

    testInputs.add(new int[] { 0, 0, 0 }); // constant sequence
    correctResults.add(false);

    testInputs.add(new int[] { 1, 2, 3, 4, 6 }); // strictly increasing
    correctResults.add(true);

    testInputs.add(new int[] { 3, 2, 1 }); // strictly decreasing
    correctResults.add(false);

    testInputs.add(new int[] { 10, 1, 2, 3 }); // first value (10) should be removed
    correctResults.add(true);

    testInputs.add(new int[] { 1, 2, 3, 1 }); // last value (1) should be removed
    correctResults.add(true);

    testInputs.add(new int[] { 1, 2, 5, 3, 5 }); // peak (5) (inner value should be removed)
    correctResults.add(true);

    testInputs.add(new int[] { 1, 2, 3, 10, 4, 4, 5 }); // peak (10) followed by constant (4)
    correctResults.add(false);

    testInputs.add(new int[] { 1, 2, 3, 1, 4, 6 }); // pit (1) (inner value should be removed)
    correctResults.add(true);

    testInputs.add(new int[] { 5, 6, 2, 6, 7 }); // pit (2) that does not recover
    correctResults.add(false);

    testInputs.add(new int[] { 5, 0, 3 }); // first value should be removed
    correctResults.add(true);

    testInputs.add(new int[] { 5, 6, 1, 2 }); // sequence downward gap (pit)
    correctResults.add(false);

    for (int i = 0; i < testInputs.size(); i++)
    {
        results.add(checkIfRemovingMaxOneElementItIsStrictlyIncreasing_NoAssignment(testInputs.get(i)));

        if (correctResults.get(i) == results.get(i))
        {
            System.out.println("Test case: " + i + " successful.");
        }
        else
        {
            System.out.println("Test case: " + i + " should be: " + correctResults.get(i) + " but was: " + results.get(i));
            System.out.println("Test case: " + i + " input array: " + Arrays.toString(testInputs.get(i)));
        }
    }
}

此外,如果您不关心某个特定值是否被破坏,则可以避免使用额外的变量:

private static boolean checkIfRemovingMaxOneElementItIsStrictlyIncreasing_WithoutAssignment(final int[] sequence)
{
    boolean isFirstNonDecreasingSequence = true;
    final int length = sequence.length;
    for (int i = 1; i < length; i++)
    {
        if (sequence[i] <= sequence[i - 1])
        {
            if (isFirstNonDecreasingSequence == true)
            {
                if ((i + 1) < length) // check this is not the last element
                {
                    if ((sequence[i - 1] >= sequence[i + 1])) // Check if it is peak or pit
                    {
                        // [i-1] is a local peak. Remove [i-1]
                        if (i > 1)
                        {
                            // Check if by removing [i-1] the sequence is actually increasing
                            if (sequence[i] <= sequence[i - 2])
                            {
                                return false;
                            }
                        }
                    }
                    else
                    {
                        // [i] is a local pit. Remove [i]
                        sequence[i] = sequence[i - 1];
                    }
                    isFirstNonDecreasingSequence = false;
                }
            }
            else
            {
                return false;
            }
        }
    }
    return true;
}

在两个版本中,代码中都有很多ifs。没错,但是只有在序列检测到两个连续值的非递增序列时,才会第一次执行它们。因此从性能角度来看应该没问题。

关于逻辑:
当它检测到在索引[i]处:A [i-1]> = A [i]时,它将确定其是否在峰值之后(因此A [i-1]“异常”高,应从索引中删除)。或它位于凹坑内(A [i]太低,应从序列中删除)。