如何查找对数组进行排序所需的最大组数?

时间:2018-03-02 22:56:56

标签: java arrays algorithm sorting grouping

假设我有一个数组:

[1, 8, 5, 6, 10, 9, 11, 12];

我想按升序排序,但找出我需要排序的最大组。在这个例子中,答案是:

[1], [8,5,6], [10,9], [11], [12]: so 5

[3,2,1]会变成1,因为整个数组都需要排序。

我完全失去了如何做到这一点,在正确的方向轻推将非常感激。

5 个答案:

答案 0 :(得分:5)

我的解决方案使用插入排序算法,它将已排序的元素保留在它们的位置,并将未排序的元素移动到数组的开头,直到它们到达它们的位置。我们可以使用此行为来检测需要排序的组。

在每次迭代中,我们检查当前元素是否大于或等于前一个元素。如果是这样,我们可能遇到了一个新组。我们将当前索引推送到堆栈。

如果当前元素小于之前的元素,那么我们仍然在同一组中。我们开始将此元素与之前的元素交换,直到它到位。在每一步,我们都会检查是否已越过前一组的边界。如果跨越边界,则意味着这两个组实际上是一个组,因此我们从堆栈中弹出最后一个值。

最后,组的数量等于堆栈大小。

以下是实施:

public static int countGroups(int[] a) {
    if (a.length < 2) return a.length;
    Stack<Integer> stack = new Stack<>();
    stack.push(0);
    for (int i = 1; i < a.length; i++) {
        if (a[i] >= a[i - 1]) stack.push(i);
        for (int j = i; j > 0 && a[j] < a[j - 1]; j--) {
            swap(a, j, j - 1);
            if (j <= stack.peek()) stack.pop();
        }
    }
    return stack.size();
}

private static void swap(int[] a, int i, int j) {
    int t = a[i];
    a[i] = a[j];
    a[j] = t;
}

以下是包含一些示例的JavaScript代码段:

&#13;
&#13;
console.log(countGroups([1, 8, 5, 6, 10, 9, 11, 12]));    //5 - [1], [8, 5, 6], [10, 9], [11], [12]
console.log(countGroups([1, 8, 5, 6, 10, 9, 2, 11, 12])); //4 - [1], [8, 5, 6, 10, 9, 2], [11], [12]
console.log(countGroups([3, 8, 5, 6, 10, 9, 2, 11, 1]));  //1 - [3, 8, 5, 6, 10, 9, 2, 11, 1]
console.log(countGroups([1, 2, 8, 6, 10, 9, 11]));        //5 - [1], [2], [8, 6], [10, 9], [11]
console.log(countGroups([1, 2, 1, 1, 10, 9, 10]));        //4 - [1], [2, 1, 1], [10, 9], [10]

function countGroups(a) {
    if (a.length < 2) return a.length;
    let stack = [0];
    for (let i = 1; i < a.length; i++) {
        if (a[i] >= a[i - 1]) stack.push(i);
        for (let j = i; j > 0 && a[j] < a[j - 1]; j--) {
            swap(a, j, j - 1);
            if (j <= stack[stack.length - 1]) stack.pop();
        }
    }
    return stack.length;
}

function swap(a, i, j) {
   let t = a[i];
   a[i] = a[j];
   a[j] = t;
}
&#13;
&#13;
&#13;

更新:如果您不需要对数组进行实际排序,那么问题似乎可以在线性时间内解决:

public static int countGroupsLinear(int[] a) {
    Stack<Integer> stack = new Stack<>();
    stack.push(a[0]);
    for (int i = 1; i < a.length; i++) {
        if (a[i] >= stack.peek()) stack.push(a[i]);
        else {
            int last = stack.pop();
            while (stack.size() > 0 && a[i] < stack.peek()) stack.pop();
            stack.push(last);
        }
    }
    return stack.size();
}

答案 1 :(得分:1)

以下代码适用于由 n 个不同整数组成的数组。这是在 C 中。

#include <stdio.h>
//code for the case where each element of the array is distinct 
//and greater than 0
//finding index of the maximum value in array
int maximum(int *a,int n)
{
    int i,max;
    max=0;
    for(i=0;i<n;i++)
    {
        if(a[i]>a[max])
        {
            max=i;
        }
    }
    return max;
}

//finding index of the minimum value in array(excluding zeros)
int minimum(int *a,int n)
{
    int i,min,index;
    min=100000;
    for(i=0;i<n;i++)
    {
        if(a[i]!=0 && a[i]<min)
        {
            min=a[i];
            index=i;
        }
    }
    return index;
}

//checks for the presence of a non-zero element in array
int check(int *a,int n)
{
    for(int i=0;i<n;i++)
    {
        if(a[i]!=0)
        return 1;
    }
    return 0;
}

//main function
int main()
{
    int n,j,k,max,min,slices;
    slices=0;
    scanf("%d",&n);
    int a[n];
    for(int j=0;j<n;j++)
    {
        scanf("%d",&a[j]);
    }
    //until all the elements of the array become 0
    //continue iterating to find slices
    while(check(a,n))
    {
        max=maximum(a,n);
        min=minimum(a,n);
        //if index of minimum value is greater than 
        //index of maximum value
        if(max<min)
        {
            slices=slices+1;
            for(j=0;j<n;j++)
            a[j]=0;
        }
        else
        {
            for(j=0;j<=min;j++)
            {
                a[j]=0;
            }
            slices=slices+1;
            if(check(a,n))
            {
                for(j=max;j<n;j++)
                {
                    a[j]=0;
                }
                slices=slices+1;
            }
        }
    }
    printf("slices %d",slices);
    return 0;
}

答案 2 :(得分:0)

此解决方案是O(N)。但是它仅适用于具有不同数字的数组。

public static List<List<Integer>> countGroups(int[] arr) {

    List<List<Integer>> result = new ArrayList<List<Integer>>();

    if (arr.length < 1)
        return result;

    // create mins from right to left
    int[] mins = new int[arr.length];
    int tempMin = arr[arr.length - 1];
    for (int i = arr.length - 1; i >= 0; i--) {
        tempMin = Math.min(tempMin, arr[i]);
        mins[i] = tempMin;
    }

    // create max from left to right
    int[] maxs = new int[arr.length];
    int tempMax = arr[0];
    for (int i = 0; i < arr.length; i++) {
        tempMax = Math.max(tempMax, arr[i]);
        maxs[i] = tempMax;
    }

    // now that you have the start of intervals (mins) and end of intervals, you can
    // simply check if you are
    // still in the interval

    List<Integer> list = new ArrayList<Integer>();
    for (int i = 0; i < arr.length - 1; i++) {
        list.add(arr[i]);
        if (mins[i] != mins[i + 1] && maxs[i] != maxs[i + 1]) {
            result.add(new ArrayList<Integer>(list));
            list.clear();
        }
    }

    list.add(arr[arr.length - 1]);
    result.add(new ArrayList<Integer>(list));

    return result;
}

`

答案 3 :(得分:0)

这是我能够提出的解决方案,其想法是保持数组的活动索引,该数组的值介于当前最大值和最小值之间,棘手的部分是使当前最大值脱离上下文为currentCheckableMaxIndex,只要它在上下文中就变成currentMaxIndex

public static int countSubArray(int[] A) {

    int len = A.length;
    int currentActiveIndex = 0;
    int count = 0;
    for(int i = 0; i < len;){
        int currentCheckableMaxIndex = i;
        int currentMinIndex = i, currentMaxIndex = i;
        for(int j = i; j < len; j++){
            // if there is a new min value, set its index,
            // also check if there is a checkable max that we can change to the new max
            if(A[currentMinIndex] > A[j]) {
                currentMinIndex = j;

                if(A[currentMaxIndex] < A[currentCheckableMaxIndex])
                    currentMaxIndex = currentCheckableMaxIndex;
            }
            // setting only the current checkable max to avoid including a max whose index is higher than current minimum
            // will only set it to the max index if there exists a new minimum whose index is > currentCheckableMaxIndex
            if(A[currentCheckableMaxIndex] < A[j]) {
                currentCheckableMaxIndex = j;
            }
            // save the current valid index only if the value in the current index is in between the current min and max
            if(A[currentMaxIndex] >= A[j] && A[j] >= A[currentMinIndex]) currentActiveIndex = j;
        }
        // i should continue from the current valid index + 1
        i = currentActiveIndex + 1;

        count++;

        // loop will not get here again if i == len - 1, so we count the last group that would have be omitted
        if(i == len - 1) {
            count++;
            break;
        }
    }

    return count;

}

答案 4 :(得分:0)

与上面提出的解决方案相同,但在 Python 3 中实现:

def solution(A) -> int:
    if len(A) < 2:
        return len(A)

    stack = [A[0]]
    for num in A[1:]:
        if num >= stack[-1]:
            stack.append(num)
        else:
            smallest = stack.pop()
            while len(stack) > 0 and num < stack[-1]:
                stack.pop()
            stack.append(smallest)
    
    return len(stack)