C++ 可折叠为单个元素的数组
这是一个面试问题,不是家庭作业 给定一个1到2^N的数组。例如:12345678(2^3)。假设这个数组写在一张纸上,我们需要把它对折,这样左半部会被镜像,然后像这样移动到右半部下面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 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
前面。现在我使用了二分法
来获得两个数组。接下来,你可能会在两个数组中找到定律。我希望这能对您有所帮助。这个问题可以通过使用堆栈和原始数组来解决。我不会为您编写解决方案,但我会指出如何解决它
- 把这段分成两半;前半部分按相反顺序(右->左)迭代,第二部分按自然顺序(左->右)迭代
- 从阵列的末尾开始向堆栈推进:
- 如果迭代为奇数,则先推奇数的一半
- 如果迭代是偶数,则先从偶数的一半开始
- 重复,并保持一半的线段,直到它们只包含一个元素;这是你的停车条件
这有点抽象,所以让我们考虑一下你的例子:
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;
}
}