面试问题......试图解决,但无法获得有效的解决方案

时间:2011-06-26 16:29:25

标签: c algorithm data-structures

我陷入了一个面试问题。问题是,

  

*给定两个数组A和B.A的整数未排序。 B也一样   长度为A,其值在   设置{-1,0,1}

     

你必须返回一个数组C.   在A上进行处理。

     

如果B [i]为0,那么C [i]必须有A [i]
  如果B [i]有-1则A [i]必须在C中   在子阵列C [0] - C [i-1]内。   离开子阵列   如果B [i]有1则A [i]   必须在子数组中的C中   C [i + 1] - C [长度(A)]即右   子阵。

     

如果不存在这样的解决方案那么   printf(“无解决方案”); *

我应用了以下逻辑: -

int indMinus1 = n-1;
int indPlus1 = 0;

//while(indPlus1 < n && indMinus1 > 0)
while(indPlus1 < indMinus1)
{
    while(b[indMinus1] != -1)   {
        if(b[indMinus1] == 0)
            c[indMinus1] = a[indMinus1];
        indMinus1--;
    }
    while(b[indPlus1] != +1)    {
        if(b[indPlus1] == 0)
            c[indPlus1] = a[indPlus1];
        indPlus1++;
    }

    c[indMinus1] = a[indPlus1];
    c[indPlus1] = a[indMinus1];
    b[indMinus1] = 0;
    b[indPlus1] = 0;
    indMinus1--;
    indPlus1++;
}

但这不会起作用,对某些情况如{1,2,3}&gt;&gt; {1,-1,-1} ......一个输出是可能的,即{2,3,1};

请帮助....他们的任何算法技术可用于此问题吗?

正确的解决方案代码

int arrange(int a[], int b[], int c[], int n)
{

for (int i = 0; i < n; ++i) {
    if(b[i] == 0)
        c[i] = a[i];
}

int ci = 0;
for (int i = 0; i < n; ++i) {
    if(b[i] == -1)  {
        while(c[ci] != 0 && ci < i)
            ci ++;
        if(c[ci] != 0 || ci >= i)
            return -1;
        c[ci] = a[i];
        ci++;
    }
}

for (int i = 0; i < n; ++i) {
    if(b[i] == 1)   {
        while(c[ci] != 0 && ci < n)
            ci ++;
        if(c[ci] != 0 || ci <= i)
            return -1;
        c[ci] = a[i];
        ci++;
    }
    }
    return 0;
}

4 个答案:

答案 0 :(得分:22)

我建议使用以下算法:
 1.最初将所有C[ i ]视为空巢  2.对于B[ i ] = 0 C[ i ] = A[ i ]我们放i的每个我  3.从左到右遍历数组 ,以及B[ i ] = -1放置的每个C[ j ] = A[ i ] 0 <= j < i,其中C[ j ]最小索引,i仍为空。如果不存在这样的指数,则答案是不可能的  4.从右到左遍历数组 ,以及B[ i ] = 1放置C[ j ] = A[ i ]的每个i < j < n,其中C[ j ]最大索引A: [ 1, 2, 3 ] B: [ 1, 1,-1 ] 仍为空。如果不存在这样的指数,答案是不可能的。

为什么我们在步骤2中将A [i]放在最左边的位置?好吧,我们知道必须将它放到某个位置j&lt;一世。另一方面,将它放在最左边将增加我们的更改,以免在步骤3中陷入困境。请参阅此示例以进行说明:

C:[ _, _, _ ]

最初C为空:A[ 2 ]
    我们没有0-s,所以让我们转到第2步     我们必须选择是将C[ 0 ]元素放置到C[ 1 ]还是C: [ _, 3, _ ]     如果我们将置于最左侧,我们将得到以下情况:
    A[ 0 ]
    并且......糟糕,由于地点不足,我们无法安排元素A[ 1 ]C: [ 3, _, _ ] :(
但是,如果我们把A [2]放在最左边,我们就会得到 C: [ 3, 1, 2 ], 并且很可能用
完成算法 O(3n) = O(n) :)。

复杂性
我们所做的是沿着数组传递三次,因此复杂度为A: [ 1, 2, 3 ] B: [ 1, -1, -1 ] - 线性。

更多示例:

C: [ _, _, _ ]

让我们一步一步地完成算法:
1. B
2.清空,因为A[ 1 ]中没有0-s 3.将A[ 2 ]C: [ 2, 3, _ ] 放在最左边的空位置:

A[ 0 ]

4。将C: [ 2, 3, 1 ] 置于最右边的自由位置(在此示例中为唯一的)自由位置:

#include <iostream>
#include <string>
#include <vector>

using namespace std;


vector< int > a;
vector< int > b;
vector< int > c;
int n;

bool solve ()
{
    int i;
    for( i = 0; i < n; ++i )
        c[ i ] = -1;
    for( i = 0; i < n; ++i )
        if( b[ i ] == 0 )
            c[ i ] = a[ i ];
    int leftmost = 0;
    for( i = 0; i < n; ++i )
        if( b[ i ] == -1 )
        {
            for( ; leftmost < i && c[ leftmost ] != -1; ++leftmost ); // finding the leftmost free cell
            if( leftmost >= i )
                return false; // not found
            c[ leftmost++ ] = a[ i ];
        }
    int rightmost = n - 1;
    for( i = n - 1; i >= 0; --i )
        if( b[ i ] == 1 )
        {
            for( ; rightmost > i && c[ rightmost ] != -1; --rightmost ); // finding the rightmost free cell
            if( rightmost <= i )
                return false; // not found;
            c[ rightmost-- ] = a[ i ];
        }
    return true;
}


int main ()
{
    cin >> n;
    a.resize(n);
    b.resize(n);
    c.resize(n);
    int i;
    for( i = 0; i < n; ++i )
        cin >> a[ i ];
    for( i = 0; i < n; ++i )
        cin >> b[ i ];
    if( !solve() )
        cout << "Impossible";
    else
        for( i = 0; i < n; ++i )
            cout << c[ i ] << ' ';
    cout << endl;
    return 0;
}

答案是什么。

源代码:

{{1}}

答案 1 :(得分:2)

花了太多时间:; - )

#include <stdint.h>
#include <string.h>
#include <stdio.h>
static int doit(int A[], int B[], int C[], size_t size)
{
    size_t first_free = size - 1;
    size_t last_free = 0;
    for (size_t i = 0; i < size; ++i) {
        if (B[i]) {
            if (i < first_free) {
                first_free = i;
            }
            if (i >= last_free) {
                last_free = i;
            }
        }
    }
    for (int i = 0; i < size; ++i) {
        if (B[i] < 0) {
            if (first_free >= i) {
                return 0;
            }
            C[first_free] = A[i];
            first_free = i;
        } else if (B[i] == 0) {
            C[i] = A[i];
        }
    }
    for (int i = size - 1; i >= 0; --i) {
        if (B[i] > 0) {
            if (last_free <= i) {
                return 0;
            }
            C[last_free] = A[i];
            last_free = i;
        }
    }
    return 1;
}
int a[] = { 1, 2, 3 };
int b[] = { 1, -1, -1 };
int c[sizeof(a) / sizeof(int)];
int main(int argc, char **argv)
{
    if (!doit(a, b, c, sizeof(a) / sizeof(int))) {
        printf("no solution");
    } else {
        for (size_t i = 0; i < sizeof(a) / sizeof(int); ++i)
            printf("c[%zu] = %d\n", i, c[i]);
    }
}

答案 2 :(得分:2)

这可以减少到网络流量。以下是构建小工具的方法:

  1. 对于A的每个元素i,创建一个节点a_i,并将一个单位容量边从源添加到a_i。

  2. 对于C的每个元素i,创建一个节点c_i,并将一个单位容量边缘从c_i添加到接收器。

  3. 对于B中索引为i的所有0个值,再次使用单位容量从a_i到c_i添加边。

  4. 对于具有索引i的B中的所有-1值,将a_j的边添加到c_i,其中0 <= j&lt;岛

  5. 对于具有索引i的B中的所有1,将a_j中的边添加到c_i,其中i <1。 j&lt; Ñ

  6. 小工具示例:

       a_0 *----* c_0
          / \    \
         /   \    \
        /     |    \
       /  a_1 | c_1 \
    S *----*  | *----* T
       \    \ \/    /
        \    \/\   /
         \   /\ | /
          \ /  \|/
           *    *
          a_2   c_2
    
    
      B = [ 0, 1, -1]
    

    此网络中容量= n的最大流量对应于a到c的赋值。要获得排列,只需计算网络的最小值即可。

答案 3 :(得分:1)

这是一个带有单个外部通道的解决方案。当i0转到n-1时,j会转到n-10lr索引指向第一个可用的“flex”点(其中b[i] != 0)。如果在任何时候l通过r,那么就没有更多的自由弹性点,并且下一次b[i] != 0外环将过早地以“无解”的方式中断。

它似乎是准确的,但是如果它在某些情况下确实失败了,那么在推进flex索引的循环中添加一些条件应该足以解决它。

将会发生一项无关的任务(b[i] == 0ci同时设置j,但它无害。 (同样适用于l > r检查。)

#include <stdio.h>

#define EMPTY 0 

int main()
{
  int a[] = {1, 2, 3};
  int b[] = {1, -1, -1};
  int c[] = {EMPTY, EMPTY, EMPTY};

  int n = sizeof(a) / sizeof(int);

  int l = 0, r = n - 1;
  int i, j;

  /* Work from both ends at once.
   *   i = 0 .. n-1
   *   j = n-1 .. 0
   *   l = left most free "flex" (c[i] != 0)  slot
   *   r = right most free flex slot
   *
   *   if (l > r) then there are no more free flex spots
   *
   *   when going right with i, check for -1 values
   *   when going left with j, check for 1 values
   *   ... but only after checking for 0 values
   */

  for (i = 0, j = n - 1; i < n; ++i, --j)
  {
    /* checking i from left to right... */
    if (b[i] == 0)
    {
      c[i] = a[i];

      /* advance l to the next free spot */
      while (l <= i && c[l] != EMPTY) ++l;
    }
    else if (b[i] == -1)
    {
      if (i <= l) break;

      c[l] = a[i];

      /* advance l to the next free spot, 
       * skipping over anything already set by c[i] = 0 */
      do ++l; while (l <= i && c[l] != EMPTY);
    }

    /* checking j from right to left... */
    if (b[j] == 0)
    {
      c[j] = a[j];
      while (r >= j && c[r] != EMPTY) --r;
    }
    else if (b[j] == 1)
    {
      if (j >= r) break;

      c[r] = a[j];
      do --r; while (r >= j && c[r] != EMPTY);
    }

    if (l > r)
    {
      /* there cannot be any more free flex spots, so
         advance l,r to the end points. */
      l = n;
      r = -1;
    }
  }

  if (i < n)
    printf("Unsolvable");
  else
  {
    for (i = 0; i < n; ++i)
      printf("%d ", c[i]);
  }

  printf("\n");

  return 0;
}