假设我有一个数组:
[1, 8, 5, 6, 10, 9, 11, 12];
我想按升序排序,但找出我需要排序的最大组。在这个例子中,答案是:
[1], [8,5,6], [10,9], [11], [12]: so 5
[3,2,1]会变成1,因为整个数组都需要排序。
我完全失去了如何做到这一点,在正确的方向轻推将非常感激。
答案 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代码段:
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;
更新:如果您不需要对数组进行实际排序,那么问题似乎可以在线性时间内解决:
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)