我有一个我正在努力的任务问题,需要一些方向来解决。 假设我有一张纸条,我将它从中心折叠,使左半部分落在右半部分后面。然后我按顺序编号折叠的peices,当我展开如下时,我得到数字。 1:2
如果我折叠两次,我会按照以下方式展开数字 1:4:3:2
如果我三次折叠,我得到如下 1 8 5 4 3 6 7 2
当我折叠n次时,我想生成数字数组。所以,如果我折叠例如25次,我会得到2 ^ 25个相似的序列号。
这些是我所做的观察
第一个和最后一个数字始终为1和2.
中间的两个数字总是4和3
索引1处的数字是最大数字,倒数第二位置的数字是第二大数字。
它看起来像二进制搜索树的前序遍历,但我不知道它有多大帮助。
编辑:为了搜索此生成的数组中的元素,我可以进行顺序搜索,这将是O(n)效率。但我意识到在这个系列中搜索一个数字必须有一个更快的方法。
我不能进行二分搜索,因为它没有排序,当完成25次折叠时,有超过十亿的数字。
我可以使用哪种搜索策略来查找数字及其索引?
这是我想将其转换为具有log(n)搜索效率的二叉搜索树的原因之一。
编辑2:我尝试了其中一个答案所建议的表格折叠算法,但它不具有内存效率。我不能在我的记忆中存储超过十亿个数字,因此必须有一种方法来查找数字索引而不实际创建数字数组。
答案 0 :(得分:6)
第1折:1 2
第二次折叠:1 4 3 2
第3折:1 8 5 4 3 6 7 2
第4折:1 16 9 8 5 12 13 4 3 14 11 6 7 10 15 2
生成表格(示例为第4折)
想象一下,你有第n张纸然后展开它。
生成一个包含大小的表(列= 1,行= 2 ^ n)并从下向上填充列,并按升序排列值
16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
通过从前到后将顶部x行粘贴到底部x行来递归调整表的大小(column = org.column * 2,row = org.row / 2)
8 9 7 10 6 11 5 12 4 13 3 14 2 15 1 16 4 13 12 5 3 14 11 6 2 15 10 7 1 16 9 8 2 15 10 7 6 11 14 3 1 16 9 8 5 12 13 4 1 16 9 8 5 12 13 4 3 14 11 6 7 10 15 2
从结尾读取最后一行表格
1 16 9 8 5 12 13 4 3 14 11 6 7 10 15 2
剩下的工作是证明这项工作然后编码(我只测试n = 4,因为我很懒)
答案 1 :(得分:5)
您可以计算折叠的数量,而无需通过使用位反转来计算整个序列(这会颠倒数字的二进制表示,以便例如0001
变为1000
)。< / p>
这些是你通过位反转获得的序列:
1 bit: 0 1
2 bits: 0 2 1 3
3 bits: 0 4 2 6 1 5 3 7
4 bits: 0 8 4 12 2 10 6 14 1 9 5 13 3 11 7 15
这些是纸张折叠序列(从0开始计算):
1 fold: 0 1
2 folds: 0 3 2 1
3 folds: 0 7 4 3 2 5 6 1
4 folds: 0 15 8 7 4 11 12 3 2 13 10 5 6 9 14 1
如果将纸张折叠序列分成偶数和奇数,则得到:
0
1
0 2
3 1
0 4 2 6
7 3 5 1
0 8 4 12 2 10 6 14
15 7 11 3 13 5 9 1
您将看到纸张折叠序列与位反转序列相同,但前半部分(偶数)与后半部分(奇数)相反。
您还会注意到,每对相邻的偶数/奇数加起来为2 n -1(其中n是折叠数),这意味着它们是彼此&# 39; s反向,你可以使用逐位NOT来计算另一个。
因此,要将折叠的折叠数x(从0开始计算)折叠n次:
将x除以2,如果x为奇数则执行按位NOT,然后按位反转(使用n位数)
示例(折叠4次):
fold x/2 binary inverted bit-reversed from 1
0 0 0000 0000 0 1
1 0 0000 1111 1111 15 16
2 1 0001 1000 8 9
3 1 0001 1110 0111 7 8
4 2 0010 0100 4 5
5 2 0010 1101 1011 11 12
6 3 0011 1100 12 13
7 3 0011 1100 0011 3 4
8 4 0100 0010 2 3
9 4 0100 1011 1101 13 14
10 5 0101 1010 10 11
11 5 0101 1010 0101 5 6
12 6 0110 0110 6 7
13 6 0110 1001 1001 9 10
14 7 0111 1110 14 15
15 7 0111 1000 0001 1 2
示例:第十亿折:(折叠30次)
fold: 1,000,000,000
counting from 0: 999,999,999 (x is odd)
x/2: 499,999,999
binary: 011101110011010110010011111111 (30 digits)
bitwise NOT: 100010001100101001101100000000 (because x was odd)
bit-reversed: 000000001101100101001100010001
decimal: 3,560,209
counting from 1: 3,560,210
我不会说Java,但是这样的事情应该可以解决问题:
public static long foldIndex(int n, long x) { // counting from zero
return Long.reverse((x & 1) == 0 ? x >>> 1 : ~(x >>> 1)) >>> (Long.SIZE - n);
}
答案 2 :(得分:2)
这是一种算法,用于查找数字之后的数字索引 展开。
它会根据折叠情况跟踪搜索号码移动到的位置的坐标。例如,如果您对3折(n = 3,numFolds
)感兴趣并且想知道数字7的位置(searchNumber
),则算法运行如下:
Initial State: 8 7 6 5 4 3 2 1 The 7 is at [1,7] - column 1, row 7 Now, when we fold the top half down: 4 5 3 6 2 7 1 8 The 7 is at [2, 1] - column 2, row 2 When we do the next fold the 7 does not move (hence the if (row > half) logic) 2 7 6 3 1 8 5 4 On the last fold: 1 8 5 4 3 6 7 2 The 7 is at [7, 1] - column 7, row 1 and the code will return 7.
public static long getIndexOfAfterFold (long numFolds, long searchNumber)
{
long total = (long) Math.pow(2, numFolds);
long [] coordsOfSearchNumber = new long [] {1, searchNumber};
int iterations = 0;
while (iterations < numFolds)
{
long half = total / 2;
long row = coordsOfSearchNumber[1];
// we are folding down
if (row > half)
{
long newRow = (total - row) + 1;
long col = coordsOfSearchNumber[0];
long newFoldThickness = (long) Math.pow(2, iterations + 1);
long newCol = newFoldThickness - (col - 1);
coordsOfSearchNumber[0] = newCol;
coordsOfSearchNumber[1] = newRow;
}
total = total / 2;
iterations++;
}
return coordsOfSearchNumber[0];
}
编辑:将上述代码转换为使用long
代替int
。
备注:
System.out.println(getIndexOfAfterFold(4, 13));
注意:这是基于@ hk6279(表格折叠算法)提供的答案
public static void unFold (int numFolds)
{
int total = (int) Math.pow(2, numFolds);
List<ArrayList<Integer>> table = new ArrayList<ArrayList<Integer>> (total);
// populate the single column table
for (int i = 0; i < total; i++)
{
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(i + 1);
table.add(list);
}
int iterations = 0;
while (iterations < numFolds)
{
int half = table.size() / 2;
// place the fold back on itself
for (int i = 0; i < half; i++)
{
ArrayList<Integer> list = table.get(i);
ArrayList<Integer> foldList = table.get(table.size() - (i + 1));
// reverse the fold
Collections.reverse(foldList);
// add the fold to front
list.addAll(foldList);
}
// remove the part we folded
table.subList(half, table.size()).clear();
iterations++;
}
System.out.println(table);
}
这就是n = 5的样子:
1,32,17,16,9,24,25,8,5,28,21,12,13,20,29,4,3,30,19,14,11,22,27,6 ,7,26,23,10,15,18,31,2
答案 3 :(得分:0)
我不了解Java,但这应该很容易移植并适用于任意数量的折叠。想法和m69一样,所以我不会自己解释逻辑。
#include <iostream>
size_t reverse(size_t n, int bits)
{
size_t result = 0;
size_t msb_value = 1 << (bits - 1);
while (n)
{
if (n & 1) result |= msb_value;
msb_value >>= 1;
n >>= 1;
}
return result;
}
struct Fold_Sequence
{
Fold_Sequence(size_t folds) : folds_(folds), max_(1 << folds) { }
size_t operator[](size_t i) const
{
size_t x = reverse((i / 2) % max_, folds_);
return i & 1 ? (max_ - x - 1) : x;
}
size_t folds_, max_, i = 0;
};
int main()
{
const size_t folds = 4;
const unsigned num_parts = 1 << folds;
Fold_Sequence seq{folds};
for (unsigned j = 0; j < num_parts; ++j)
std::cout << seq[j] + 1 << '\n';
}
我也喜欢hk6279解决方案的优雅,所以我实现了它(也是在C ++中,我懒得使用多维数组/ vector<vector<>>
并且必须小心地调整大小,因此使用map
键入x,y坐标来实现效率低下:
#include <iostream>
#include <map>
#define DBG(X) do { std::cout << X << '\n'; } while (false)
typedef std::pair<size_t, size_t> Coord;
struct matrix : std::map<Coord, size_t>
{
matrix(size_t n)
: y_size_(n)
{
for (size_t i = 0; i < n; ++i)
(*this)[{0, i}] = i; // bottom left is 0,0; 0,1 is above
}
void fold()
{
size_t x_size_ = x_size();
for (size_t y = y_size_ / 2; y < y_size_; ++y)
for (size_t x = 0; x < x_size_; ++x)
move(x, y, x_size_ * 2 - x - 1, y_size_ - y - 1);
y_size_ /= 2;
}
void move(size_t from_x, size_t from_y, size_t to_x, size_t to_y)
{
DBG("move(" << from_x << ',' << from_y << " -> " << to_x << ',' << to_y
<< ") value " << ((*this)[{from_x, from_y}]));
(*this)[{to_x, to_y}] = (*this)[{from_x, from_y}];
erase({from_x, from_y});
}
size_t operator()(size_t x, size_t y) const
{
auto it = find({x, y});
if (it != end()) return it->second;
std::cerr << "m(" << x << ',' << y << ") doesn't exist\n";
exit(1);
}
size_t x_size() const { return size() / y_size_; }
size_t y_size() const { return y_size_; }
size_t y_size_;
};
std::ostream& operator<<(std::ostream& os, const matrix& m)
{
for (size_t y = m.y_size_ - 1; y <= m.y_size_; --y)
{
for (size_t x = 0; x < m.x_size(); ++x)
os << m(x, y) << ' ';
os << '\n';
}
return os;
}
int main()
{
const size_t n = 4;
matrix m(1 << n);
for (int i = 0; i < n; ++i)
{
m.fold();
std::cout << i+1 << " folds ==> " << m.x_size() << 'x' << m.y_size()
<< " matrix:\n" << m << '\n';
}
}