【问题标题】:Array folding into a single element数组折叠成单个元素
【发布时间】:2015-10-18 13:13:38
【问题描述】:

这是一道面试题,不是作业。

给定一个 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的数组中

迭代:

折叠头部数组,对于每个折叠,前半部分和后半部分标题将被链接。链接后从头数组中删除头指针。

继续直到 w 在头数组中有一个头指针。

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

【问题讨论】:

  • 在第一步中,您将后半部分移到开头,然后将前半部分反转。在第二步中,前半部分 (5, 6) 保持原位,而不是推动后半部分的前面。在第三次迭代中,后半部分 (6) 再次移到前面。
  • 在这种情况下堆栈是什么意思?是 push/pop 结构,还是 CPU 堆栈(无动态分配)?
  • push/pop 结构很可能
  • 你说想象数组是写在纸上的,但是如果你折叠一张纸,你不会在第二次折叠时得到那个顺序。 1 会在 8 之上,2 会在 7 之上。你有没有搞错问题?
  • @DouglasZare,我已对其进行了编辑以尝试更清楚地解释它。我有理由确定我已经理解 OP 的初衷。在每次迭代中,方向(左对右)都会发生变化,这是我一开始没有注意到的,但在原文中。

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


【解决方案1】:

这个问题可以通过使用堆栈和原始数组来解决。我不会为你编写解决方案,但我会指出如何解决它。

  1. 按照我们将进一步讨论的规则将数组元素推入堆栈
  2. 紧接着将堆栈弹出回数组,从索引 0 开始
  3. 重复直到满足结束条件

填充堆栈的规则:

  • 最初将您的数组视为一个“段”
  • 将段分成两半;前半部分您将按相反顺序(右->左)进行迭代,第二个按自然顺序(左->右)
  • 你从数组的末尾开始压栈:

    • 如果迭代是奇数,先推奇数的一半,

    • 如果迭代是偶数,先从偶数一半开始

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

这有点抽象,所以让我们考虑一下您的示例:

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 &lt;-56 -&gt;78 &lt;-43 -&gt;21;奇数一半56,43;偶数一半78,21

从头开始填充堆栈;国际米兰是偶数,从上半场开始

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

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

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

iter=3 -&gt;5 &lt;-6 -&gt;4 &lt;-3 -&gt;8 &lt;-7 -&gt;1 &lt;-2

iter 是奇数,所以先填充堆栈的奇数部分

 6
 3
 7
 2 
 5
 4
 8 
 1

弹回堆栈,你就完成了:63725481

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      也许你的面试官期望的是:

      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;
            }
          }
      

      { 证明您了解堆栈和递归 ;-) }

      【讨论】:

      • 感谢您的来信;对语言感到抱歉(没有注意规范的那部分),猜测受访者将能够用 C++ 重新表述它。
      【解决方案4】:

      这是一个递归解决方案变成了迭代;因此是一个堆栈,尽管可能不是预期的那样。该函数根据给定位置返回元素的起始位置。似乎是时间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)
      

      【讨论】:

        猜你喜欢
        • 2015-10-13
        • 2020-09-15
        • 2015-02-09
        • 1970-01-01
        • 2016-12-09
        • 2013-04-08
        • 2012-12-07
        • 2015-12-19
        • 1970-01-01
        相关资源
        最近更新 更多