Java 在数组中查找和最小的两个非后续元素

Java 在数组中查找和最小的两个非后续元素,java,arrays,algorithm,time-complexity,minimum,Java,Arrays,Algorithm,Time Complexity,Minimum,简介:据我所知,这个问题还没有被问到。 这是一个面试问题。 我甚至没有特别寻找代码解决方案,任何算法/伪代码都可以 问题:给定一个整数数组int[]A及其大小N,找到2个非后续的(不能在数组中相邻)元素的最小和。此外,答案不得包含第一个或最后一个元素(索引0和n-1)。此外,解决方案应为O(n)时间和空间复杂性 例如,当A=[5,2,4,6,3,7]时,答案是5,因为2+3=5 当A=[1,2,3,3,2,1]时,答案是4,因为2+2=4,并且您不能选择1中的任何一个,因为它们位于数组的末端

简介:据我所知,这个问题还没有被问到。
这是一个面试问题。
我甚至没有特别寻找代码解决方案,任何算法/伪代码都可以


问题:给定一个整数数组
int[]A
及其大小
N
,找到2个非后续的(不能在数组中相邻)元素的最小和。此外,答案不得包含第一个或最后一个元素(索引
0
n-1
)。此外,解决方案应为
O(n)
时间和空间复杂性

例如,当
A=[5,2,4,6,3,7]
时,答案是
5
,因为
2+3=5

A=[1,2,3,3,2,1]
时,答案是
4
,因为
2+2=4
,并且您不能选择
1
中的任何一个,因为它们位于数组的末端


尝试:起初,我认为解决方案中的一个数字必须是数组中最小的一个(除了第一个和最后一个),但反例很快反驳了这一点
A=[4,2,1,2,4]
->4(2+2)

然后我想如果我在数组中找到2最小的数字(除了第一个和最后一个),那么解决方案就是这两个。这显然很快就失败了,因为我不能选择两个相邻的数字,如果我必须选择非相邻的数字,那么这就是问题的定义:)

最后我想,好吧,我将在数组中找到3最小的数字(除了第一个和最后一个),解决方案必须是其中的两个,因为其中的两个必须不相邻。 由于
A=[2,2,1,2,4,2,6]
->2+1=3
,这个也失败了,因为我会找到
2,1,2
,但假设我在索引
1,2,3
中找到
2,1,2
,这不一定会起作用(如果我在索引
5
中特别找到
2
,我会这样做,但不幸的是,我不能保证这一点)


问题:
现在我被难住了,有人能想出一个可行的解决方案/想法吗?

编辑:没错,我完全忽略了邻接约束。 幸运的是,我想到了一个解决办法。 算法如下所示:

public class Main {

    int solve(int[] array) {
        int answer = Integer.MAX_VALUE;
        int min = array[1];
        for (int i = 3; i < array.length - 1; i++) {
            min = Math.min(min, array[i - 2]);
            if (array[i] + min < answer) {
                answer = array[i] + min;
            }
        }
        return answer;
    }
}
  • 在数组上运行一次以查找最小的
    (O(n))
  • 您再次运行以查找第二个最小的
    (O(n))
  • 如果第二个最小值与最小值不相邻,我们就完成了(
    O(1)
    -只是索引检查)
  • 否则,运行第三次以查找第三个最小值(仍然
    O(n)
  • 如果不与最小值相邻,则返回最小值和第三小值 否则返回第二和第三个最小值

  • 找到四个最小值,考虑四个之间的所有可能性。最小的不相邻于最小的第二个、第三个或最小第四个;另一个可能更好的是第二个和最小的第三个(假设它们是不相邻的)。(或者更准确地说是它们的索引)(

    k
    足够大,比如说
    10
    )。可以肯定的是,想要的一对在它们之间。现在您只需检查可能的
    50
    对,并选择满足约束的最佳对

    您不需要
    10
    ,只需要更少,但需要更多
    3
    :)

    编辑:查找
    k
    最小的数字是
    O(n)
    ,因为您只需在堆中保留最好的
    10
    (添加新元素,删除最大
    O(k*logk)=O(1)
    操作)

    然后将有一对满足约束条件(彼此不相邻)。同样清楚的是,如果使用不是从
    k
    元素中选择的元素构建总和,那么它将大于从
    k
    元素中选择的最佳对


    最多检查
    k*k
    对也是
    O(1)
    ,因此整个运行时间是
    O(n)

    我认为这应该是可行的:

    找到最小的3个元素及其索引。因为它们不能都是相邻的,所以从中选择2个

    如果它们都是相邻的,最小数在中间,则遍历所有元素,找到第四个最小元素,选择最小值<代码> MI1+MI4,<代码> MIN2+MI3,无论哪个较小。 您也可以在一次迭代中完成此操作。

    算法:

  • 找到最小值,避免结束索引。(1 O(n)通过)
  • 求最小值,避开末端索引和(1)的索引以及相邻索引。(1 O(n)通过)
  • 求最小值,避开末端索引和(1)(1 O(n)次)的索引
  • 求最小值,避开末端索引和(3)索引以及相邻索引。(1 O(n)通过)
  • 返回总和(1)+(2)、(3)+(4)中的最小值(如果存在)
  • 通过3和4意味着通过查找2来通过案例[4,2,1,2,4]=4

    public static int minSumNonAdjNonEnd(int[] array)
    {
        // 1. Find minimum
        int minIdx1 = -1;
        int minValue1 = Integer.MAX_VALUE;
        for (int i = 1; i < array.length - 1; i++)
        {
            if (array[i] < minValue1)
            {
                minIdx1 = i;
                minValue1 = array[i];
            }
        }
        // 2. Find minimum not among (1) or adjacents.
        int minIdx2 = -1;
        int minValue2 = Integer.MAX_VALUE;
        for (int i = 1; i < array.length - 1; i++)
        {
            if ((i < minIdx1 - 1 || i > minIdx1 + 1) && (array[i] < minValue2))
            {
                minIdx2 = i;
                minValue2 = array[i];
            }
        }
        boolean sum1Exists = (minIdx1 > -1 && minIdx2 > -1);
        int sum1 = minValue1 + minValue2;
    
        // 3. Find minimum not among (1).
        int minIdx3 = -1;
        int minValue3 = Integer.MAX_VALUE;
        for (int i = 1; i < array.length - 1; i++)
        {
            if ((i != minIdx1) && (array[i] < minValue3))
            {
                minIdx3 = i;
                minValue3 = array[i];
            }
        }
    
        // 4. Find minimum not among(3) or adjacents.
        int minIdx4 = -1;
        int minValue4 = Integer.MAX_VALUE;
        for (int i = 1; i < array.length - 1; i++)
        {
            if ((i < minIdx3 - 1 || i > minIdx3 + 1) && (array[i] < minValue4))
            {
                minIdx4 = i;
                minValue4 = array[i];
            }
        }
        boolean sum2Exists = (minIdx3 > -1 && minIdx4 > -1);
        int sum2 = minValue3 + minValue4;
    
        if (sum1Exists)
        {
            if (sum2Exists)
                return Math.min(sum1, sum2);
            else
                return sum1;
        }
        else
        {
            if (sum2Exists)
                return sum2;
            else
                throw new IllegalArgumentException("impossible");
        }
    }
    

    以下是一个算法的实时javascript实现:

    • 查找4个最小的元素(不包括搜索中的第一个/最后一个元素)
    • 查找在原始数组中不相邻的这4个元素对
    • 从这些对中查找具有最小和的对
    函数findMinNoNajacentPair(a){
    var mins=[];
    //快速出口:
    if(a.length<5)返回{error:“没有解决方案,元素太少。”};
    if(a.some(isNaN))返回{error:“给定的非数值。”};
    //按索引收集4个最小值
    对于(var i=1;istatic void printMinimalSum(int[] A) {  
        // Looking for mins so we init this with max value
        int[] mins = new int[]{Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MAX_VALUE};
        // Indices, used just to print the solution
        int[] indices = new int[]{-1, -1, -1};
        // If the array has length 5 then there's only one solution with the 2nd and 4th elements
        if (A.length == 5) {
            mins[0] = A[1];
            indices[0] = 1;
            mins[1] = A[3];
            indices[1] = 3;
        } else {        
            // Loop on the array without considering the first and the last element
            for (int i = 1; i < A.length - 1; i++) {
                // We consider each element which is smaller than its neighbours
                if ((i == 1 && A[i] < A[i + 1]) // 1: first element, compare it with the second one
                        || (i == A.length - 2 && A[i] < A[i - 1]) // 2: last element, compare it with the previous one
                        || (A[i] < A[i + 1] && A[i] < A[i - 1])) { // 3: mid element, compare it with both neighbors
                    // If the element is "legal" then we see if it's smaller than the 3 already saved
                    if (A[i] < mins[0]) {
                        mins[0] = A[i];
                        indices[0] = i;
                    } else if (A[i] < mins[1]) {
                        mins[1] = A[i];
                        indices[1] = i;
                    } else if (A[i] < mins[2]) {
                        mins[2] = A[i];
                        indices[2] = i;
                    }
                }
            }
        }     
        // Compute the 3 sums between those 3 elements
        int[] sums = new int[]{Math.abs(mins[0]+mins[1]), Math.abs(mins[0]+mins[2]), Math.abs(mins[1]+mins[2])};
        // Find the smaller sum and print it
        if (sums[0] < sums[1] || sums[0] < sums[2]){
            System.out.println("Sum = " + sums[0] + " (elements = {" + mins[0] + "," + mins[1] + "}, indices = {" + indices[0] + "," + indices[1] + "}");
        } else if (sums[1] < sums[0] || sums[1] < sums[2]){
            System.out.println("Sum = " + sums[1] + " (elements = {" + mins[0] + "," + mins[2] + "}, indices = {" + indices[0] + "," + indices[2] + "}");
        } else {
            System.out.println("Sum = " + sums[2] + " (elements = {" + mins[1] + "," + mins[2] + "}, indices = {" + indices[1] + "," + indices[2] + "}");
        }
    }
    
    public static void main(String[] args) {
        printMinimalSum(new int[]{5, 2, 4, 6, 3, 7});
        printMinimalSum(new int[]{1, 2, 3, 3, 2, 1});
        printMinimalSum(new int[]{4, 2, 1, 2, 4});
        printMinimalSum(new int[]{2, 2, 1, 2, 4, 2, 6});
    }
    
    Sum = 5 (elements = {2,3}, indices = {1,4}
    Sum = 4 (elements = {2,2}, indices = {1,4}
    Sum = 4 (elements = {2,2}, indices = {1,3}
    Sum = 3 (elements = {1,2}, indices = {2,5}
    
    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};
    }
    
    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.");
    }
    
    DP[i] = min(DP[i-1], min(first_data, second_data))
    
        import random
        def get_min(numbers):
                #disregard the first and last element
                numbers = numbers[1:len(numbers)-1]
                #for remembering the past results
                DP = [0]*len(numbers)
                #for keeping track of minimum till now found
                table = [0]*len(numbers)
                high_number = 1 << 30
    
                min_number = numbers[0]
                table[0] = min_number
                for i in range(0, len(numbers)):
                        DP[i] = high_number
                for i in range(1, len(numbers)):
                        if numbers[i] < min_number:
                                min_number = numbers[i]
                                table[i] = numbers[i]
                        else:
                                table[i] = min_number
                for i in range(0, len(numbers)):
                        min_first, min_second = high_number, high_number
                        if i >= 2:
                                min_first = numbers[i] + table[i-2]
                        if i >= 3:
                                min_second = numbers[i-1] + table[i-3]
                        if i >= 1:
                                DP[i] = min(min(DP[i-1], min_first), min_second)
                return DP[len(numbers)-1]
    
        input = random.sample(range(100), 10)
        print(input)
        print(get_min(input))
    
    public class Main {
    
        int solve(int[] array) {
            int answer = Integer.MAX_VALUE;
            for (int i = 3; i < array.length - 1; i++) {
                for (int j = 1; j < i - 1; j++) {
                    if (array[i] + array[j] < answer) {
                        answer = array[i] + array[j];
                    }
                }
            }
            return answer;
        }
    }
    
    public class Main {
    
        int solve(int[] array) {
            int answer = Integer.MAX_VALUE;
            int min = array[1];
            for (int i = 3; i < array.length - 1; i++) {
                min = Math.min(min, array[i - 2]);
                if (array[i] + min < answer) {
                    answer = array[i] + min;
                }
            }
            return answer;
        }
    }
    
        int minSum(int[] A){
            int minSum=Integer.MAX_VALUE;
            int min= Integer.MAX_VALUE;
            for(int i=3; i<A.length-1; i++){
                min= Math.min(A[i-2], min);
                minSum = Math.min(min+A[i], minSum);
            }
            return minSum;
        }