查找数组分区,其中max(left)< min(右) - 可能在O(N)时间?

时间:2017-10-11 13:11:16

标签: algorithm time-complexity

我刚刚尝试编写一个编码挑战来编写一个函数,该函数返回数字数组的最短可能左分区的长度,其所有元素都小于相应右分区中的所有元素。

考虑到每月温度读数的变化数量,给出了“冬季”和“夏季”之间的差异,并规定所有冬季温度均低于夏季全部温度。我们可以假设至少有一个正确的分区,目标是获得最短的冬天。

是否可以在O(N)时间内完成此操作,即处理时间随温度读数的数量线性增加?我能想出的最快的解决方案是找到每个最大冬季温度的最低夏季温度(右侧分区的最低数量):

function shortestWinterLength temps
    maxWinterTemp = -Infinity

    for i from 0 til temps.length
        minSummerTemp = Infinity

        for j from i + 1 til temps.length
            minSummerTemp = Math.min minSummerTemp, temps[j]

        maxWinterTemp = Math.max maxWinterTemp, temps[i]

        if maxWinterTemp < minSummerTemp
            return i + 1

7 个答案:

答案 0 :(得分:4)

是的,O(n)解决方案是可行的,但需要额外的内存。

让我们填充数组minR minR[i] = min(A[i], ..., A[n])

可以在O(n)中计算此数组的值。我们只是以相反的顺序遍历初始数组,并计算最后一个数组元素中的最小值:

minR[n-1] = a[n-1]
for i from n-2 downto 0 
    minR[i] = min(minR[i+1], A[i])

然后你需要的是遍历数组,计算第一个i数组元素中的最大值,并将此值与minR[i+1]进行比较:

maxL = 0
for i from 0 to n-2
    maxL = max(maxL, A[i])
    if maxL < minR[i+1] then 
        outputResult(i)

答案 1 :(得分:3)

计算min(temps [i + 1],... temps [n])的问题中提到的方法是低效的,因为对不同的 i 值进行了许多类似的比较。

相反,所有“min”值都可以通过执行单个数组传递获得,但是从右向左迭代

因此,有必要从右到左执行初始传递,这将存储到目前为止在辅助阵列中达到的最小值。之后,您可以在当前解决方案中使用与i相同的循环,但只需从刚刚计算的辅助数组中检索“min”,就可以替换j上的内循环。

此解决方案具有O(n)复杂度。

答案 2 :(得分:2)

代码:

def shortestWinterLength(listofTemperatures):

    if len(listofTemperatures) == 0 :
        return 0

    length = len(listofTemperatures)
    winter_high = listofTemperatures[0]
    overall_high = listofTemperatures[0]
    winter_length = 0

    # Get max in the left array  
    for temperature in listofTemperatures:
        if temperature <= winter_high : 
            winter_high = overall_high
        elif temperature > overall_high :
            overall_high = temperature

    # count all the values which are less than max in left array
    for temperature in listofTemperatures :
        if temperature <= winter_high : 
            winter_length += 1

    # total length of the left array
    return winter_length

时间复杂度 - O(n)
空间复杂性 - O(1)

答案 3 :(得分:2)

这是O(n)时间和O(1)空间复杂度的C ++代码。

int solution(vector<int> &A) {

        int leftMax = A[0];     //  Max temperature during winter
        int maximum = A[0];     //  Max temperature during the year
        int position = 1;       //  Possible solution

        int n = A.size();

        for(int i = 1; i < n; i++) {
            if (A[i] < leftMax) {
                position = i+1;      // got a new lower value
                leftMax = maximum;
            } else if (A[i] > maximum) {
                maximum = A[i];
            }
        }        
        return position;
    }

答案 4 :(得分:0)

C中的代码:

int arr[] = { -5, -5, -5, -42,  6 , 120 };

int  winter_high[6] =  { NULL };
int  overall_high[6] = { NULL };

int j,k; 

  winter_high[0] = arr[0];
  overall_high[0] = arr[0];

for (int i = 0; i < 6 ; i++)
{
    if (arr[i] <= winter_high[j])
    {
        winter_high[j] = arr[i];
        j++;
    }


    else if (arr[i] > overall_high[k])
    {
        overall_high[k] = arr[i];
        k++;
    }
}

printf("The length of the winter sub array: %d ", j);
printf("The length of the summer sub array: %d ", k);

答案 5 :(得分:0)

找到时间最短O(n)的Java程序:

public static void main(String[] args) {

    int[] A = {4, 3, 2, 5, 8, 6, 7};
    //int[] A = {-3, -2, 3, 4, 6};
    int n = A.length; 
    System.out.println(FindElement(A, n));

}

static int FindElement(int[] A, int n) 
{ 
    // Create an array 'SE[]' that will  
    // store smaller element on right side. 
    int[] SE = new int[n]; 

    // Create an another array 'GE[]' that  
    // will store greatest element on left side. 
    int[] GE = new int[n]; 

    // initialize first and last index of SE[], GE[] 
    GE[0] = A[0]; 
    SE[n - 1] = A[n - 1]; 

    // store greatest element from left to right 
    for (int i = 1; i < n; i++)  
    { 
        if (GE[i - 1] < A[i]) 
            GE[i] = A[i]; 
        else
            GE[i] = GE[i - 1]; 
    } 

    // store smallest element from right to left 
    for (int i = n - 2; i >= 0; i--)  
    { 
        if (A[i] < SE[i + 1]) 
            SE[i] = A[i]; 
        else
            SE[i] = SE[i + 1]; 
    } 

    // Now find a number which is greater then all 
    // elements at it's left and smaller the all 
    // then elements to it's right 
    for (int j = 0; j < n; j++)  
    { 
        if (j == 0) {
            if (A[j] < SE[j + 1])
            return j+1;
        } else if(j == n - 1) {
            if(A[j] > GE[j - 1]) {
                return j;
            }
        } else if(GE[j - 1] < SE[j] && A[j] > GE[j - 1]) {
            return j;
        }           

    } 

    return -1; 
}

答案 6 :(得分:0)

在这里,我将分享我的两个解决方案(使用Java),以解决“冬季之夏”的Codility问题。我用了第二个,得分为100%:

/**
 * Time Complexity: O(n) Space Complexity: O(n)
 * <p>
 * This version uses an auxiliary array to calculate all the possible summer mins.It is good enough but it is not so memory-efficient and that might be crucial as the size of the input size increases, so I went ahead and tried an in-place solution, which is the one I am exhibiting as "the" solution at {@link
 * #shortestWinterLengthOnePass(int[])} (see below)
 */
private static int shortestWinterLengthAuxArray(int[] temperatures) {
    int n = temperatures.length;

    if (n <= 1) {
        return n;
    }
    int[] summerMin = calculateAllPossibleMinimums(temperatures);

    int winterMax = Integer.MIN_VALUE;
    for (int i = 0; i < n - 1; i++) {
        winterMax = Math.max(temperatures[i], winterMax);

        if (winterMax < summerMin[i + 1]) {
            return i + 1;
        }
    }
    return n;
}

/**
 * Dynamic Programming: calculate all possible minimums from every position, in order to avoid double iterations on
 * the main algorithm, avoiding a time complexity of O(n^2).
 *
 * @param temperatures the array of temperatures to scan
 *
 * @return an array that, on its "i" position, will hold the minimums from temperatures[i]...temperatures[n-1]
 */
private static int[] calculateAllPossibleMinimums(int[] temperatures) {
    int n = temperatures.length;
    int[] summerMin = new int[n]; // auxiliary array. position "i" will hold the minimums from i...n-1
    summerMin[n - 1] = temperatures[n - 1];

    for (int i = n - 2; i >= 0; i--) {
        summerMin[i] = Math.min(temperatures[i], summerMin[i + 1]);
    }
    return summerMin;
}

现在,我的首选解决方案是:

/**
 * This is my second stab at the problem, that iterates the input array only once. It has:
 * <p>
 * Time Complexity: O(n) Space Complexity: O(1)
 */
private static int shortestWinterLengthOnePass(int[] temperatures) {
    int n = temperatures.length;

    if (n == 0) {
        return 0;
    }
    int winterHighest = temperatures[0];
    int currentOverallHighest = temperatures[0];
    int winterLength = n;

    // Establish the max temperature in the winter partition so that winterHighest < "the lowest of summer"
    for (int i = 0; i < n; i++) {
        int current = temperatures[i];

        if (current <= winterHighest) {
            // found something lower than our current highest, it must be included in the "winter" (left) partition
            winterHighest = currentOverallHighest;
            winterLength = i + 1;   // keep track of the (last) position where the above realization happened
        } else if (current > currentOverallHighest) {
            currentOverallHighest = current;
        }
    }
    return winterLength;
}