【问题标题】:Algorithm - Maximum left sub-array with lesser elements算法 - 具有较少元素的最大左子数组
【发布时间】:2017-08-09 07:48:59
【问题描述】:

我正在开发一个程序,我需要获取整数数组中元素的索引,以便索引右侧的所有元素都大于从0 到该索引位置的所有元素。

例如:

Case : 1 - 给定输入 - { 5, -2, 3, 8, 6 } 然后我需要索引位置为 2 (i.e array element with value 3) 因为索引 2 之后的所有元素都大于从索引 0 到索引 2 的所有元素,即 {5,- 2,3}

Case : 2 - 给定输入 - { -5, 3, -2, 8, 6 } 然后我需要索引位置为 2 (i.e array element with value -2) 因为索引 2 之后的所有元素都大于从索引 0 到索引 2 的所有元素,即 {-5, 3,-2}

这是我的 Java 程序:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class ArrayProgram {

    public static void main(String[] args) {
        int[] array1 = { 5, -2, 3, 8, 6 };
        int[] array2 = { -5, 3, -2, 8, 6 };
        process(array1);
        process(array2);
    }

    private static void process(int[] array) {
        List<Integer> list = new ArrayList<Integer>();
        int maxIndex = 0;
        list.add(array[0]);
        System.out.println(Arrays.toString(array));
        for (int i = 1; i < array.length; i++) {
            if (array[i] <= Collections.max(list)) {
                list.add(array[i]);
                maxIndex = i;
            }
        }

        System.out.println("index = " + maxIndex + ", element = " + array[maxIndex]);
    }
}

程序输出为:

[5, -2, 3, 8, 6]
index = 2, element = 3
[-5, 3, -2, 8, 6]
index = 0, element = -5

它适用于case 1,但不适用于case 2。你能帮我解决这个问题吗?有没有其他更好的方法来解决这个问题,

【问题讨论】:

  • 这个算法不能正常工作。是你自己发明的还是来自其他网站?
  • @ByeBye 我刚刚拍摄了一个场景并尝试实现它,它仅适用于少数情况
  • 因为你需要计算我建议在地图中使用的所有可能性,并在最后得到最小值
  • array2[0] 中的值为 -5(负数)。在您的第二个示例中,值为 5(正)。所以你的程序似乎可以正常工作(因为索引 1 > 索引 0 的值)
  • 在情况 2 中,数组以 5 开头,而在代码中,array2 以 -5 开头

标签: java arrays algorithm


【解决方案1】:

很遗憾,您的解决方案有几个逻辑错误。反例之一:[2, 1, 3, 6, 5](您的算法返回索引1,但答案是2)。

我提出另一个具有O(n)时间复杂度的解决方案:

  1. 从左到右迭代计算[0..i] 区间中元素的最大值。
  2. 从右到左迭代计算[i+1..n] 区间中的最小元素,并将该最小值与在第一步预先计算的左侧元素的最大值进行比较。

示例实现:

static void process(int[] array) {
    int n = array.length;
    if (n < 2) return;

    int[] maxLeft = new int[n];
    maxLeft[0] = array[0];
    for (int i = 1; i < n; ++i) {
        maxLeft[i] = Math.max(maxLeft[i-1], array[i]);
    }  

    int minRight = array[array.length-1];
    for (int i = n-2; i >= 0; --i) {
        if (maxLeft[i] < minRight) {
            System.out.println("index = " + i + ", element = " + array[i]);
            return;
        } 
        minRight = Math.min(minRight, array[i]); 
    }
}    

可运行:http://ideone.com/mmfvmH

【讨论】:

  • 如果分区来自第(n-2)个元素,只需要添加一个打印案例,例如 int[] array1 = { 3, -2, 3, -2, 3 };
  • @Hakes,但这个案子没有答案。来自问题:“我需要在整数数组中获取元素的索引,以使索引右侧的所有元素都大于从 0 到该索引位置的所有元素”。
  • 是的,你是对的大于,不是大于或等于,我的错误。
  • @DAle,谢谢。你能给我推荐一本关于算法的好书吗,我尝试向coreman学习,但我无法从中理解任何东西。
  • @user3181365,不客气! 《算法导论》是一本很棒的书,曾经是我个人的选择。可能有些 Robert Sedgewick 或 Niklaus Wirth 的书对您有帮助。
【解决方案2】:

将我的评论更改为回答。从数组的末尾开始,右边只有一个元素,左边有 n - 1 个元素。然后检查左边的最大值

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class ArrayProgram {

    public static void main(String[] args) {
        int[] array1 = { 5, -2, 3, 8, 6 };
        int[] array2 = { -5, 3, -2, 8, 6 };
        int[] array3 = { 1, 3, 5, 8, 4 };
        int[] array4 = { 1, 1, 1, 1, 1 };
        process(array1);
        process(array2);
        process(array3);
        process(array4);
    }


    private static void process(int[] array) {
        List<Integer> listLeft = new ArrayList<Integer>();
        List<Integer> listRight = new ArrayList<Integer>();

        //create an array that consists upto n-1 elements
        int arraySize = array.length;
        if ( arraySize < 2){
            System.out.println("None");
            return;
        }
        for ( int i = 0; i < arraySize - 1; i++){
            listLeft.add ( array[i]);
        }
        //create an array that has the last element
        listRight.add ( array[arraySize - 1]);

        //iterate from the last adding new elements till the condition satisfies
        for ( int i = arraySize - 2; i >= 0; i--){

            //if the condition is satisfied exit
            if ( Collections.max(listLeft) < Collections.min(listRight)){
                System.out.println("index = " + i + ", element = " + array[i]);
                return;
            }else{
                //remove an element from left and add an element to right
                listLeft.remove (listLeft.size() - 1);
                listRight.add ( array[i]);
            }
        }

        System.out.println("None");
    }
}

【讨论】:

    【解决方案3】:

    我会建议一种算法来获得正确的输出。它将在 O(n) 中执行。让我们考虑在arr[] 中有n 元素。维护 2 个数组 int minElementIndex[]maxElementIndex[]

    • minElementIndex[i] 存储子数组 [(i+1) ... (n-1)] 中存在的最小值元素的索引。 minElementIndex[n-1]=n-1的值
    • maxElementIndex[i] 存储子数组 [0 ... (i)] 中存在的最大值元素的索引。 maxElementIndex[0]=0的值

    填充minElementIndex[0...n-1]的代码

    int index=minElementIndex[n-1];
    for(int i=n-2;i>=0;i--){
      minElementIndex[i] = index;
      if(arr[i]<arr[index])
          index=i;
    }
    

    填充maxElementIndex[0 ... n-1]的代码:

    int index=maxElementIndex[0];
    for(int i=1;i<n;i++){
      if(arr[i]>arr[index])
         index=i;
      maxElementIndex[i]=index;
    }
    

    现在,只需按以下方式遍历两个数组:

    for(int i=1;i<n-1;i++){ 
        if(arr[maxElementIndex[i]]< minElementIndex[i]){
            System.out.println(i);
        }
    }
    

    让我们试运行提出的算法。

    案例 1: arr[5] = {5,-2,3,8,6} minElementIndex[5] = {1,2,4,4,4}maxElementIndex[5] = {0,0,0,3,3}。显然是i=2arr[maxElementIndex[i]] &lt; arr[minElementIndex[i]],即5 &lt; 6

    案例 2: arr[5] = {-5,3,-2,8,6} minElementIndex[5] = {2,2,4,4,4}maxElementIndex[5] = {0,1,1,3,3}。显然是i=2arr[maxElementIndex[i]] &lt; arr[minElementIndex[i]],即3 &lt; 6

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-07
      • 2017-01-17
      • 1970-01-01
      • 1970-01-01
      • 2013-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多