Algorithm 排列0';标准普尔;1';在一个数组中

Algorithm 排列0';标准普尔;1';在一个数组中,algorithm,language-agnostic,Algorithm,Language Agnostic,这是我最近的一个面试问题之一。我想知道其他人对这个问题的看法 问题: 您将获得一个包含员工详细信息的结构,其中包含两个元素,intdepartment和stringname struct Employee { string Name; int Dept; } 给您提供了N名员工的详细信息,其中N/2名员工的Dept==0,N/2名员工的Dept==1,按任意顺序排列。您需要根据员工的Dept值对员工详细信息进行排序,也就是说,应保持原始记录中1和0的顺序 例如,给定以下示例数

这是我最近的一个面试问题之一。我想知道其他人对这个问题的看法

问题:

您将获得一个包含员工详细信息的结构,其中包含两个元素,
int
department和
string
name

struct Employee
{ 
    string Name;
    int Dept;
}
给您提供了N名员工的详细信息,其中N/2名员工的
Dept==0
,N/2名员工的
Dept==1
,按任意顺序排列。您需要根据员工的
Dept
值对员工详细信息进行排序,也就是说,应保持原始记录中1和0的顺序

例如,给定以下示例数据:

Name Dept X1 0 X2 1 X3 0 X4 1 X5 0 姓名部门 x10 X2 1 X3 0 X4 1 X5 0 排序后,结果应为:

Name Dept X2 1 X4 1 X1 0 X3 0 X5 0 姓名部门 X2 1 X4 1 x10 X3 0 X5 0 算法应该是稳定的,时间复杂度应该是O(N),为其他变量提供恒定的空间(这意味着排序应该在适当的位置进行)。

分配第二个数组(O(N))。迭代第一个数组,并按第二个数组中出现的顺序移动所有1。再次迭代并将按相同顺序保留的0移动到第二个数组。所有操作为O(N)。这不是原位(就地)解决方案。通过运行一次快速排序分割算法,可获得非稳定的原位解

经过一些研究,似乎没有任何额外内存的已知O(N)解是不稳定的。学术界对有效的0-1稳定原位排序(就地)进行了研究,但解决方案需要一些额外的内存。我想知道最初的问题陈述是否没有以准确的方式复制。没有稳定性要求,问题很容易解决;它也很容易,无需现场要求。由于这两种要求(原位、稳定),解决方案似乎难以实现


在这里的答案中,有一个算法可以在O(N)中工作,并且是原位的,但是只有当关键字段(1)是可变的并且(2)可以包含整数而不是单个位时。这是可行的,但不是原位0-1稳定排序,因为假定每个数组元素都有O(log N)个可写内存。

原始问题文本没有提到除整数以外的任何其他字段(此后已编辑)


在这种情况下,稳定性是没有意义的,因为两个相等的数字在其他方面是无法区分的。解决方案是只遍历数组,然后将1的n/2次放入,然后将0的n/2次放入。

抽象地说,您可以使用修改后的插入排序,将所有零值向右交换,将所有一个值向左交换。然而,这将具有比O(n)更大的复杂性

我有点困惑,为什么排序很重要,正如前面所说,字节是无法区分的

编辑:新的示例很有帮助。我的算法的好处是,即使在最坏的情况下它比线性时间慢,但它的内存使用率只有O(n)。由于1和0只是较大对象(可能任意大)的键,内存可能是一个问题。

简单:

function sort(array):
    new_array = new Array(array.length)
    x = 0
    for(i : array): if(i): new_array(x++) = 1
    return new_array
如果你真的想要相同的1和0:

function sort(array):
    new_array = new Array(array.length)
    x, y = 0, array.length / 2
    for(i : array):
        if(i): new_array(x++) = i
        else:  new_array(y++) = i
    return new_array

使用
std::stable_partition
以及
std::equal_to
std::binder1st
应该以一种很好的、功能性的、类似STL的方式来完成这项任务:

using namespace std
stable_partition(&array[0], &array[N], binder1st(equal_to(), 1));
当然,这假设数组的元素定义了一些比较运算符(即,您可以说
array[i]==1
…)。如果它们只是整数,那么维持顺序就没有任何意义了


至于复杂性:为了成为O(N),
稳定分区
需要额外的内存。如果算法无法分配额外的内存,它将在O(N log N)中执行。

好的,下面是我的方法

e、 g a[]={1,0,0,0,1,1,1,0,0,1}

伪代码:

  • 有两个计数器,
    count1=0
    count2=(n/2)+1
  • 穿过阵列

    if(arr[ i ] == 1) 
    { 
        arr[ i ] = count1++;
    } else { 
        arr[ i ] = count2++ 
    };
    
  • 在遍历结束时,数组中填充了数字0到n-1,如:

    a[ ] = { 0, 5, 6, 7, 1, 2, 3, 8, 9 4}
    
  • 现在问题是如何对上述结果数组进行排序,这可以在O(N)中完成,如下所示:

    for(j = 0; j <= 1; j++)  
    {
        for(i = 0; i<n; i++)  
        {  
            if(arr[ i ] != i)  
            {  
                swap(arr[ i ], arr[ arr[ i ] ]);  
            }  
        }  
    }
    

    for(j=0;j为了简单起见,使用了整数而不是位,但基本概念是相同的。不同的1和0的顺序并不重要

    var emps = new[] 
               {
                   new Employee(X1, 0),
                   new Employee(X2, 1),
                   new Employee(X3, 0),
                   new Employee(X4, 1),
                   new Employee(X5, 0),
                   new Employee(X6, 1)
               };
    
    var sortedEmps = new Employee[bits.Length];
    
    var oneIndex = 0;
    var zeroIndex = bits.Length/2;
    
    foreach (var employee in employees)
    {
        if (employee.Dept  == 1)
            sortedEmps[oneIndex++] = employee;
        else
            sortedEmps[zeroIndex++] = employee;
    }
    
    更新以解决员工问题。添加了一名额外员工,因为原始问题表示每个问题都有N/2名员工,因此必须有一个偶数才能为真。否则情况相同


    不确定现在是否可以编译,所以将其视为伪代码!

    见鬼,以下是完整的解决方案: arr是项目列表,item.id为0或1,存储为int。
    此代码将0移到前面

    count = { 0:0, 1:len(arr)/2 }
    for ii in range(len( arr )):
      id = arr[ii].id
      arr[ii].id = count[id]
      count[id] += 1
    for ii in range(len( arr )):
      while arr[ii].id != ii:
        T = arr[ii]
        arr[ii] = arr[arr[ii].id]
        arr[T.id] = T
    for ii in range(len( arr )):
      arr[ii].id = (ii >= len(arr)/2)
    
    这是我的(完整的)在C#中尝试一下。它会生成一个列表并随机加入员工,所以你可以随意制作
    numberOfEmployees
    。我意识到可能有一种更简单的方法可以做到这一点,因为最初的海报规定0部门员工与1部门员工数量相等,但我无法控制自己

    struct Employee
    {
        public Employee(string name, int dept)
        {
            this.name = name;
            this.dept = dept;
        }
    
        public string name;
        public int dept;
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            int numberOfEmployees = 100;
            Random r = new Random();
    
            Employee[] emps = new Employee[numberOfEmployees];
            var empBuf = new Employee[numberOfEmployees];
            int nextAvail = 0;
    
            // Initialize array of employees with random data
            for (int i = 0; i < numberOfEmployees; i++)
            {
                emps[i] = new Employee("x" + i.ToString(), r.Next(0, 2));
            }
    
            Console.WriteLine("Old list:");
            foreach (var e in emps)
            {
                Console.WriteLine("Name: {0}, Dept: {1}", e.name, e.dept);
            }
    
            // throw employees with dept == 1 in first
            for (int i = 0; i < numberOfEmployees; i++)
            {
                if (emps[i].dept == 1)
                {
                    empBuf[nextAvail] = emps[i];
                    nextAvail++;
                }
            }
    
            // stick the employees with dept == 0 in last
            for (int i = 0; i < numberOfEmployees; i++)
            {
                if (emps[i].dept == 0)
                {
                    empBuf[nextAvail] = emps[i];
                    nextAvail++;
                }
            }
    
    
            Console.WriteLine("New list:");
            foreach (Employee e in empBuf)
            {
                Console.WriteLine("Name: {0}, Dept: {1}", e.name, e.dept);
            }
    
        }
    }
    
    struct Employee
    {
    公共员工(字符串名称,内部部门)
    {
    this.name=名称;
    this.dept=dept;
    }
    公共字符串名称;
    公共关系部;
    }
    班级计划
    {
    静态void Main(字符串[]参数)
    {
    int numberOfEmployees=100;
    随机r=新随机();
    员工[]emps=新员工[员工人数];
    var empBuf=新员工[员工人数];
    int-nextAvail=0;
    //使用随机数据初始化员工数组
    对于(int i=0;iuse Modern::Perl;
    
    my @data;
    {
      use List::MoreUtils qw'natatime';
      my $iter = natatime 2, qw'
        X1  0
        X2  1
        X3  0
        X4  1
        X5  0
      ';
    
      while( my($a,$b) = $iter->() ){
        push @data, [$a,$b]
      }
    }
    
    my @sorted = sort {
      ($a->[1] <=> $b->[1]) * -2 + # gives more weight to second element
      ($a->[0] cmp $b->[0])
    } @data;
    
    say "Name\tDept\n";
    say join "\t", @$_ for @sorted;
    
    Name Dept X2 1 X4 1 X1 0 X3 0 X5 0
     a           b        a1      b1     a0     b0
    X1,0   ->   X2,1      0   --> 1      X1 <-  X2
    X3,0   ->   X4,1      0   --> 1      X3 <-  X4
    X2,1  <-    X4,1      1   -   1      X2 <-  X4
    X4,1  <-    X1,0      1 <--   0      X4  -> X1
    X1,0  <-    X3,0      0   -   0      X1 <-  X3
    X2,1 <<-    X5,0      1 <--   0      X2 <-  X5
    X5,0   ->>  X4,1      0   --> 1      X5  -> X4
    X5,0   ->   X1,0      0   -   0      X5  -> X1
    X5,0   ->   X3,0      0   -   0      X5  -> X3
    
    The arrows point at the earlier value.
    
    sort (int [] a) {
       int pos = 0;
       for (int i = 1; i < a.length; i++) {
           if (a[i] == 0 && a[pos] == 1) {
               swap(a, pos, i);   // this makes all 0's go to the left.
               pos++;
           }
       } 
    }
    
    #include<stdio.h>
    //#include<conio.h>
    
    int main()
    {
      int i,a[20]={0};
      int *ptr1,*ptr2;
      //clrscr();
      //a[2]=a[4]=a[6]=a[8]=a[16]=1;
      a[19]=a[18]=1;
    
      for(i=0;i<20;i++)
        printf("%d",a[i]);
    
      printf("\n\nafter");
    
      ptr1=ptr2=a;
      for(i=0;i<20;i++)
      {
        if(*ptr1==0&&*ptr2==1)
        {
          int temp=*ptr1;*ptr1=*ptr2;*ptr2=temp;
          ptr1++;ptr2++;
        }
        else if(*ptr1==1&&*ptr2==0)
        {
          ptr1++;ptr2++;
        }
        else if(*ptr1==0&&*ptr2==0)
        {
          ptr2++;
        }
        else
        {
          if(ptr1<ptr2)
            ptr1++;
          else
          {
            ptr1++;ptr2++;
          }
        }
      }
    
      for(i=0;i<20;i++)
      {
        printf("%d",a[i]);
      }
    
     // getch();
    
      return 0;
    }
    
        while(s less than end)
        {
            if(list[s]==1)
            {
                while(list[end] == 1) 
                   end--;
    
                if(list[end] == 0 && s less than end)
                {
                    tmp = list[s];
                    list[s] = list[end];
                    list[end] = tmp;
                    s++;end--;
                }
            }
            else s++;
        }
        for(s=0;s less than N;s++)
        {
            printf("%d ",list[s]);
        }
        return;
    }
    
    private static int[] foo(int[] array) {
    
    int counter = 0;
    int i;
    
    for(i = 0; i < array.length; i++) {
    if (array[i] == 1) {
        array[i] = 0;
        counter++;      
    }
    }
    
    while(counter > 0) {
    array[--i] = 1;
    counter--;
    }
    return array;
    }
    
    left = 0;
    right = n-1;
    
    while(left<right){
    
    while(left < right && array[left]==0){
        left++;
    }
    
    while(left < right && array[right]==1){
        right--;
    }
    
    while(left<right){
        array[left]=0;
        array[right]=1;
        left++;
        right--;    
    }
    
    }