按相对位置排序数组

时间:2012-03-12 04:45:51

标签: algorithm position sorting

给出一个具有负整数和正整数的数组,实现花费O(n)时间和O(1)空间的算法,使所有正整数前面都有负整数,并保持相对位置。 例如:{1,7,-5,9,-12,15} -----> {-5,-12,1,7,9,15}

你有什么想法吗?

4 个答案:

答案 0 :(得分:5)

您要求稳定的就地分区功能。

论文Stable Minimum Space Partitioning in Linear Time (1992)声称拥有此类算法,但有些other SO questions对其可行性提出质疑。

答案 1 :(得分:1)

我对算法的想法:

具有类似于基于分区的一般选择的轴心点。 http://en.wikipedia.org/wiki/Selection_algorithm

围绕枢轴交换值进行旋转,直到所有负数都在数组的一个分区中(后面有所有正数...或者可能包围它)

然而,这种交换会略微影响订购。 我将解释如何纠正负数的排序(并且你也会这样做以纠正正数的排序)。

每次交换两个号码时,请更改号码的符号。

这意味着如果您通过负数分区,那么所有正数都是交换的负数。这意味着正数和下一个正数之间的所有负数应该在第一个正数之前。通过并交换所有(连续不应该太多,所以你应该得到O(N))

negs = -4,-5,-6
pos = 1,2,3
ans = -4,-5,-6,1,2,3

1,2,-4,-5,3,-6

i->-4  j->-5
-4 and -5 are both negative.. decrease i by one

1,2,-4,-5,3,-6
i->2 j->-5
swap.

1,5,-4,-2,3,-6
i->1 j->3
1 and 3 are both positive, increase j by one (take turns at changing i,j)

1,5,-4,-2,3,-6
i->1 j->-6
swap.

6,5,-4,-2,3,-1

#now we have negs at start, pos at end of array.
#now do corrections using signs as notification of what was swapped
#we had a counter that told us there were 3 negs.and 3 pos.
#fix first 3 negs.. 6,5,-4 should go to -4,-5,-6
(can tell order by. non swapped negs always come before swapped negs..in the order they are in.. negs are in reverse order)
i'll leave you to implement algorithm for it.

答案 2 :(得分:0)

这段代码大部分都在那里..我只是没有完成它反转x,j和j,y之间的交换值的部分。 (你可以反转......我还没做到这一点。)

无论如何......恐怕我没时间完成它,但希望你能:

def brute_force(nums):
    neg = [i for i in nums if i<0]
    pos = [i for i in nums if i>=0]
    return neg+pos

def in_place(nums,i,j,depth):
    x,y = i,j
    print 'running on ',nums[i:j+1]
    if j-i==1:
        a,b = nums[i],nums[j]
        if a>=0 and b<0:
            nums[i],nums[j] = b,a
        return None
    #print i,j
    while i<j:
        a,b = nums[i],nums[j]
        if (a<0 and b>=0):
            i+=1
            j-=1
        elif (a>=0 and b<0):
            nums[i],nums[j]=-b,-a
            i+=1
            j-=1
        elif a<0:
            i+=1
        else:
            j-=1
    print "changed1 to ", nums
    print nums[x:j+1],nums[j+1:y+1]
    start = (i for i in reversed(nums[x:j+1]) if i>=0)
    for i in range(x,j):
        if nums[i]>=0:
            nums[i]=next(start)
    print "changed2 to ", nums
    end = (i for i in reversed(nums[j+1:y+1]) if i<0)
    for i in range(j+1,y+1):
        if nums[i]<0:
            nums[i]=next(end)
    print "changed3 to ", nums
    if depth == 0:
        in_place(nums,0,j,depth+1)
        in_place(nums,j+1,len(nums)-1,depth+1)







nums = [1,2,-4,-5,3,-6]

print brute_force(nums)
in_place(nums,0,len(nums)-1,0)
print nums
print "going z"
#z = [-2,3,-1]
#in_place(z,0,2,0)
#print z

进一步的例子:

_list = [1,-4,2,-5,3,-6]

def in_place(nums,i,j,depth):
    x,y = i,j
    print 'running on ',nums[i:j+1]
    if j-i==1:
        a,b = nums[i],nums[j]
        if a>=0 and b<0:
            nums[i],nums[j] = b,a
        return None
    #print i,j
    while i<j:
        a,b = nums[i],nums[j]
        if (a<0 and b>=0):
            i+=1
            j-=1
        elif (a>=0 and b<0):
            nums[i],nums[j]=-b,-a
            i+=1
            j-=1
        elif a<0:
            i+=1
        else:
            j-=1
    print "changed1 to ", nums

in_place(_list,0,len(_list)-1,0)

>>>
running on  [1, -4, 2, -5, 3, -6]
changed1 to  [6, -4, 5, -2, 3, -1]

答案 3 :(得分:0)

这可以通过在合并排序算法中改变合并功能来完成。

输入:int [] A,int low,int mid,int high

开始前循环变化: A [low]到A [mid]的-ve数跟在+ ve数后面,并且数字最初出现在A [low]到A [mid]中。
上述条件适用于A [mid + 1]到A [high]

合并步骤:

  1. 跳过-ve之间低至中间的所有元素,保存+ ve数字的起点,如变量j所示。
  2. 复制在中间到临时数组之前+ ve的剩余元素
  3. 从A [j]开始,将所有-ve元素复制到mid + 1到high的范围内,同时递增j
  4. 将存储在临时数组中的元素复制回A继续j
  5. A的后半部分+ ve元素已经到位,所以不需要做任何事情

    public static void rearrange(int[] a){
        merge_arrange(a, 0, a.length-1);
    }
    
    public static void merge_arrange(int[] a, int low, int high){
        if(low < high){
            int mid = (low+high)/2;
            merge_arrange(a, low, mid);
            merge_arrange(a, mid+1, high);
    
            merge(a, low, mid, high);
        }
    }
    
    public static void merge(int[] a, int low, int mid, int high){
        ArrayList<Integer> temp = new ArrayList<Integer>();
    
        int i;
        for(i=low;i<=mid && a[i]<0;i++);
    
        int j=i;
        while(i<=mid){
            temp.add(a[i++]);
        }
    
        int k;
        for(k=mid+1;k<=high && a[k]<0;k++){
            a[j] = a[k];
            j++;
        }
    
        for(int num:temp){
            a[j] = num;
            j++;
        }
    }