Finding two non-subsequent elements in array which sum is minimal

前端 未结 13 988
小蘑菇
小蘑菇 2021-02-05 03:40

Intro: As far as I could search, this question wasn\'t asked in SO yet.
This is an interview question.
I am not even specifically looking for a code sol

相关标签:
13条回答
  • 2021-02-05 04:05

    Use dynamic programming.

    1. Remove or disregard the first and last elements of your array. Since they cannot participate in the solution, they are not important. Once you've done this, you can also ignore the "must not be the first or last element" constraint since we've already accounted for it.
    2. Find the solution for the first three elements of (what's left of) the array (and without considering the "no first/last element" rule). There is only one solution in this case (array[0] + array[2]), so this is a trivial step.
    3. Memoize the minimal element which is not the last element (i.e. min(array[0], array[1])).
    4. Find the solution for the first four elements. We don't have to redo the whole problem; instead we just have to ask whether introducing the fourth element allows us to produce a smaller solution. We can do this by adding the fourth element to the minimal element we memoized in the previous step, and comparing the sum to the solution we found in the second step.
    5. Update the memoized minimal element so that it is the minimum of the first three elements.
    6. Continue widening and updating in this fashion until we have considered the entire array.

    The whole algorithm is O(n), since both widening and updating are constant-time operations. The algorithm can be proved correct by simple induction. O(n) is also a lower bound since we have to consider every element of the array, so this algorithm is optimal.

    0 讨论(0)
  • 2021-02-05 04:06

    Find the four smallest and consider all possibilities among those four. The smallest is nonadjacent to at least one of the second, third, or fourth smallest; the only other possibility that could be better is the second and third smallest (assuming that they are nonadjacent).

    0 讨论(0)
  • 2021-02-05 04:06

    How about that: you find k smallest numbers (or more precisely their indices) (k big enough, let say 10). It is sure, that the wanted pair is between them. Now you just check the possible 50 pairs and select the best which satisfies the constraints.

    You don't need 10, less would do - but more than 3 :)

    Edit: finding k smallest numbers is O(n), because you just keep the best 10 for example in a heap (add new element, delete maximum O(k*logk)=O(1) operations).

    Then there will be a pair which satisfy the constraints (not next to each other). It is also clear that, if you build the sum with an element not from those k, it would be bigger than the best pair chosen from those k elements.

    Checking at most k*k pairs is also O(1), thus the whole running time is O(n).

    0 讨论(0)
  • 2021-02-05 04:07

    edit: you're right, I completely ignored the adjacency constraint. luckily I've thought of a solution. The algorithm goes like this:

    1. You run once over the array to find the smallest (O(n))
    2. You run a second time to find the second smallest (O(n))
    3. If second smallest is not adjacent to smallest we're done(O(1) - just an index check)
    4. Otherwise run a third time to find third smallest (still O(n))
    5. If not adjacent to smallest return smallest and third smallest otherwise return second and third smallest
    0 讨论(0)
  • 2021-02-05 04:09

    I think this does not need any deep reasoning, and can be solved in a single pass, keeping the optimal solution of the array elements processed so far:

    public static int[] minimumSumOfNonAcjacentElements(int[] a) {
        // the result for the sequence a[1:i]
        int minSum = Integer.MAX_VALUE;
        int minSumElement1 = Integer.MAX_VALUE;
        int minSumElement2 = Integer.MAX_VALUE;
    
        // the minimum element eligible for joining with a[i], i.e. from a[1 : i-2]
        int minElement = a[1];
    
        int prevElement = a[2]; // a[i - 1]
        for (int i = 3; i + 1 < a.length; i++) {
            int sum = minElement + a[i];
            if (sum < minSum) {
                minSum = sum;
                minSumElement1 = minElement;
                minSumElement2 = a[i];
            }
    
            if (prevElement < minElement) {
                minElement = prevElement;
            }
            prevElement = a[i];
        }
    
        return new int[] {minSumElement1, minSumElement2};
    }
    

    Here's some test code, with the corner cases from OP's question:

    private static void test(int minSumIndex1, int minSumIndex2, int... input) {
        int[] result = minimumSumOfNonAcjacentElements(input);
        if (result[0] == minSumIndex1 && result[1] == minSumIndex2) {
            // ok
        } else {
            throw new AssertionError("Expected: " + minSumIndex1 + ", " + minSumIndex2 + ". Actual=" + Arrays.toString(result));
        }
    }
    
    public static void main(String[] args) throws Exception {
        test(2, 2, 4, 2, 1, 2, 4);
        test(1, 2, 2, 2, 1, 2, 4, 2, 6);
        test(1, 2, 0, 2, 1, 2, 4, 2, 0);
        System.out.println("All tests passed.");
    }
    
    0 讨论(0)
  • 2021-02-05 04:12
    1. Find the smallest number beside the first and the last.
    2. Find the second smallest that is not a neighbour of the first one and not the first or last one in the array. Then build the sum.

      • If the first element is the second or the penultimate element you already have the solution.
    3. Otherwise calculate the sum of both neighbours of the first number. check if its smaller then the first sum

      • if not: take the first sum
      • otherwise take the second one

    This will always work because if the first sum is not the answer that means the first number cannot be part of the solution. And that on the other hand means, the solution can just be the second sum.

    0 讨论(0)
提交回复
热议问题