C++ 可折叠为单个元素的数组

C++ 可折叠为单个元素的数组,c++,arrays,algorithm,pointers,data-structures,C++,Arrays,Algorithm,Pointers,Data Structures,这是一个面试问题,不是家庭作业 给定一个1到2^N的数组。例如:12345678(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 纸张必须折叠,每次都要改变方向(左对右),直到我们将所有元素都

这是一个面试问题,不是家庭作业

给定一个1到2^N的数组。例如:12345678(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后,从headarray中删除head指针

继续,直到在head数组中有一个head指针


但是面试官让我在堆栈中解决它。有谁能帮我在堆栈中解决这个问题,并指出我的解决方案中是否有错误。提前谢谢

我发现了一条定律,数组中的元素,其索引是
(2*n-1,2*n)
,而
n
是奇数,无论折叠方向如何,总是在其余元素之前排列。例如,数组
12345678
,元素
2367
始终位于
1458
前面。现在我使用了
二分法
来获得两个数组。接下来,你可能会在两个数组中找到定律。我希望这能对您有所帮助。

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

  • 按照我们将进一步讨论的规则将数组元素推送到堆栈上
  • 紧接着,从索引0开始将堆栈放回数组中
  • 重复此步骤,直到满足结束条件
  • 填充堆栈的规则:

      最初考虑数组为“段”< /LI>
    • 把这段分成两半;前半部分按相反顺序(右->左)迭代,第二部分按自然顺序(左->右)迭代
    • 从阵列的末尾开始向堆栈推进:

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

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

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

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


    iter=1
    ->1234
    5
    4
    8
    1
    也许你的面试官期望的是:

    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;
          }
        }
    
    private int[]折叠(int-pow)
    {
    如果(功率<0)
    抛出新异常(“非法输入”);
    int n=1;
    
    对于(int factor=1;factor,这里是一个递归的迭代解决方案;因此是一个堆栈,尽管可能不是预期的。该函数根据给定位置返回元素的起始位置。它似乎是时间
    O(1/2n(logn+1))
    和空间
    O(logn)

    JavaScript代码:

    函数f(n,y,x,l){ 变量堆栈=[[n,y,x,l]]; while(堆栈[0]){ var temp=stack.pop(); 变量n=temp[0],y=temp[1],x=temp[2],l=temp[3]; var m=1 m/2) 堆栈推送([n*2,y-m/2,n+n-x+1,l-1]); 其他的 堆栈推送([n*2,y,x,l-1]); }如果(y>m/2),则为其他情况{ 堆栈推送([n*2,y-m/2,n-x+1,l-1]); }否则 堆栈推送([n*2,y,x+n,l-1]); } } 函数g(p){
    var n=1在第一步中,您在开始时移动后半部分,并反转第一步。在第二步中,前半部分(5,6)保持在原位,而不是向前推后半部分。在第三次迭代中,后半部分(6)再次向前移动。在这种情况下,堆栈意味着什么?是推送/弹出结构,还是CPU堆栈(无动态分配)?推送/弹出结构最有可能你说的是想象数组是写在纸上的,但是如果你折叠一张纸,你在第二次折叠时就得不到这个顺序。1会在8以上,2会在7以上。你把问题搞错了吗?@DouglasZare,我编辑它是为了更清楚地解释它。我有理由相信我没有理解它在每次迭代中,方向(左vs右)改变,这是我最初没有注意到的,但是它是在原文中。感谢注释;对语言(没有注意到这部分的规范)感到抱歉,猜测被采访者将能够在C++中重新编写它。
    5 
    6
    4 
    3
    8 <-even halfs end, odd halfs start 
    7
    1 
    2
    
     6
     3
     7
     2 
     5
     4
     8 
     1
    
    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;
          }
        }