数组折叠成单个元素

时间:2015-07-28 06:10:08

标签: c++ arrays algorithm pointers data-structures

这是一个面试问题而不是作业。

给定1到2 ^ N的数组。例如:1 2 3 4 5 6 7 8(2 ^ 3)。想象这个数组写在纸上,我们需要将它折叠成一半,这样左半部分就会被镜像,然后移动到右半部分下方此

1 2 3 4 5 6 7 8
 left  |  right
 half  |  half

变为

5 6 7 8
4 3 2 1

然后下一个折叠我们将右侧改为一半,镜像并将其移动到左半部分之下,

 5 6 
 4 3 
 8 7
 1 2 

纸张必须折叠,每次都改变方向(左 - 右 - 右),直到我们在这一列中包含所有元素

 6
 3
 7 
 2
 5
 4
 8 
 1 

我的解决方案, 第一步 : 为原始数组的后半部分创建链接列表,并反转前半部分并将其与头部指针连接,

5 6 7 8 
| | | |
4 3 2 1

将链表的头指针存储在名为headarray

的数组中

迭代地说:

折叠头部阵列,对于每个折叠,前半部分和后半部分头部将被链接。链接后删除headarray的头指针。

继续,直到头部阵列中有一个头部指针。

但是面试官让我把它解决了。任何人都可以帮助解决堆栈中的问题,并指出我的解决方案是否有任何错误。提前致谢。

4 个答案:

答案 0 :(得分:2)

使用堆栈和原始数组可以解决此问题。我不会为您编写解决方案,但我会指出如何解决它。

  1. 按照我们将进一步讨论的规则
  2. 将数组元素推送到堆栈
  3. 之后,将堆栈弹回到从索引0开始的数组
  4. 重复直至完成最终条件
  5. 填写筹码的规则:

    • 最初将您的数组视为一个'段'
    • 将该段分成两半;上半部分将以相反顺序(右 - >左)迭代,第二部分按自然顺序(左 - >右)
    • 您开始从阵列末尾继续前进到堆栈:

      • 如果迭代为奇数,则首先推动奇数半部分,

      • 如果迭代甚至以偶数的一半开始

    • 重复,并保持段的一半,直到它们只包含一个元素;这是你的停止条件

    这有点抽象,所以让我们考虑你的例子:

    iter = 1 ->1234 <-5678箭头表示迭代的方向

    从最后开始并填充堆栈; inter是奇数,所以从遇到的第一个奇数半开始

    5
    6
    7
    8
    4  <-notice that the order of pushing the halfs on the stack is shown by the arrows
    3
    2
    1
    

    弹回堆栈:5 6 7 8 4 3 2 1

    继续划分半场:

    iter = 2 <-56 ->78 <-43 ->21;奇数半身5643;甚至一半7821

    从最后开始并填充堆栈;国际米兰甚至从第一个偶数半开始

    5 
    6
    4 
    3
    8 <-even halfs end, odd halfs start 
    7
    1 
    2
    

    重新弹出堆栈:5 6 4 3 8 7 1 2

    再次划分细分,因为每个新半部分中只有一个元素,箭头仅用于突出显示规则:

    iter = 3 ->5 <-6 ->4 <-3 ->8 <-7 ->1 <-2

    iter很奇怪,所以首先填充堆栈奇数半个

     6
     3
     7
     2 
     5
     4
     8 
     1
    

    重新弹出堆栈,完成后:63725481

    我希望这是有道理的;快乐的编码:)

答案 1 :(得分:0)

我找到了一个定律,即数组中的元素,其索引为(2*n-1, 2*n)n为奇数,总是在其余元素之前排列你所折叠的方向。例如,数组12345678,元素2367始终位于1458的前面。现在我使用dichotomy来获取两个数组。接下来你可能会发现两个阵列中的定律。我希望这可以帮到你。

答案 2 :(得分:0)

也许你的面试官期望这样:

private int[] Fold(int pow)
   {
      if (pow < 0)
        throw new Exception("illegal input");

      int n = 1;
      for (int factor = 1; factor <= pow; factor++)
        n *= 2;

      Stack<int> storage = new Stack<int>(n);

      this.Add(n, 1, storage);

      int[] result = new int[n];
      for (int k = 0; k < n; k++)
        result[k] = storage.Pop();

      return result;
    }

    private void Add(int n, int value, Stack<int> storage)
    {
      storage.Push(value);

      int m = n;
      while (true)
      {
        int mirror = m + 1 - value;
        if (mirror <= value)
          break;
        this.Add(n, mirror, storage);
        m /= 2;
      }
    }

{证明你知道堆栈和递归;-)}

答案 3 :(得分:0)

这是一个迭代的递归解决方案;因此堆栈,虽然可能不是预期的。该函数根据给定的位置返回元素的起始位置。它似乎是时间O(1/2n(log n + 1))和空格O(log n)

JavaScript代码:

function f(n,y,x,l){
  var stack = [[n,y,x,l]];
  while (stack[0]){
    var temp = stack.pop();
    var n = temp[0], y = temp[1], x = temp[2], l = temp[3];
    var m = 1 << l;
    if (m == 1)
      return x;
    if (l % 2 == 0){
      if (y > m / 2)
        stack.push([n * 2,y - m / 2,n + n - x + 1,l - 1]);
      else
        stack.push([n * 2,y,x,l - 1]);
    } else if (y > m / 2){
      stack.push([n * 2,y - m / 2,n - x + 1,l - 1]);
    } else
      stack.push([n * 2,y,x + n,l - 1]);
  }
}

function g(p){
  var n = 1 << p;
  for (var i=1; i<n; i+=2){
    var a = f(1,i,1,p);
    console.log(a);
    console.log(n - a + 1);
  }
}

g(3)