将一个整数范围可逆地映射到另一个整数范围的算法?

时间:2017-08-25 16:56:32

标签: algorithm math integer discrete-mathematics

什么是时间效率和节省空间的算法,用于将离散范围的整数(比如间隔I1 [A..B],其中B> = A)线性映射到另一个更大的整数范围(比如一个区间) I2 [C..D]其中D> = C)?

为了简单地在此呈现,第二范围I2的大小被约束为大于或等于第一范围I1,换句话说,D-C> = B-A。

因此,I1中的每个整数映射到I2中包含的一个或多个相应整数的集合(因为I2的大小大于I1的大小)。相反,I2中的每个整数都映射回I1中恰好一个唯一的对应整数。

因此,存在两种期望的算法,其在两个提供的整数间隔的域中操作:间隔I1 [A..B]和间隔I2 [C..D](其中B> = A且D> = C和DC> = BA)

  1. 算法A1:给定I1中包含的整数X,计算I2中相应的线性映射整数集。将其表示为A1(I1,I2,X)= [M..N],其中[M..N]是I2的子间隔。

  2. 算法A2:给定区间I2中包含的整数Y,计算I1中的单个对应整数。将其表示为A2(I1,I2,Y)= X。

  3. 算法A2必须是A1的对称逆。也就是说,对于I1中的所有X:A1(I1,I2,X)= [M..N],则对于[M..N]中的所有Y:A2(I1,I2,Y)= X

    显然,由于此问题仅限于整数,因此映射可能不完全是线性的。例如,如果I1包含三个整数[1..3],而I2包含四个整数[4..7],则I1中的两个整数将在I2中具有单个映射,而I1中的第三个整数将具有I2中的两个映射。来自I1的具有两个映射的特定整数是无关紧要的。重要的是,无论算法A1选择哪个整数(X)具有两个映射(Y和Y + 1),算法A2必须将相同的两个Y值从I1映射回原始X.

    算法A1和A2应该创建从I1到I2的最可能的线性映射。换句话说,如果间隔I1具有大小J并且间隔I2具有大小K(并且回想起K> = J),则I1的每个整数具有TRUNC(K / J)映射或TRUNC(K / J)+1映射。进入I2。

    算法应该消耗恒定的空间,因此由一组代数方程组成,这些方程可能使用截断整数除法和模运算,以及其他基本数学函数。换句话说,算法不能为需要空间来存储表中每个映射的映射创建表,因为整数区间的大小可以达到2 ^ 64.

    编辑:例如,假设间隔I1 = [0..2]且间隔I2 = [0..4]。一个正确的解决方案可能是:

    Algorithm A1                    Algorithm A2
    X=0, Y=[0..1]                   Y=0, X=0
    X=1, Y=[2..3]                   Y=1, X=0
    X=2, Y=[4]                      Y=2, X=1
                                    Y=3, X=1
                                    Y=4, X=2
    

    另一个同样正确的解决方案是:

    Algorithm A1                    Algorithm A2
    X=0, Y=0                        Y=0, X=0
    X=1, Y=[1..2]                   Y=1, X=1
    X=2, Y=[3..4]                   Y=2, X=1
                                    Y=3, X=2
                                    Y=4, X=2
    

    INCORRECT解决方案将是:

    Algorithm A1                    Algorithm A2
    X=0, Y=[0..1]                   Y=0, X=0
    X=1, Y=[2..3]                   Y=1, X=1
    X=2, Y=[4]                      Y=2, X=1
                                    Y=3, X=2
                                    Y=4, X=2
    

    上述解决方案不正确。虽然A1确实将[0..2]线性映射到[0..4],而A2确实将[0..4]线性地映射回[0..2],但问题是A2不是A1的倒数。例如,对于X = 0,A1(0)的一个值是Y = 1,但A2(1)给出X = 1(而不是原始值0)。

2 个答案:

答案 0 :(得分:1)

我建议使用模块化映射,而不是使用区间和截断,只需按照数字顺序将 i1 的元素映射到 i2 ,然后根据需要进行换行。这是Python中的代码(为了清晰和通用,有一些过于简单和冗余的赋值),以及范围[2:5]和[4:13]

的示例

代码:

def alg_1(x, interval_1, interval_2):
# Map X, an element of interval 1,
#   to a list of elements in interval 2.

    lo_1 = interval_1[0]
    hi_1 = interval_1[1]
    lo_2 = interval_2[0]
    hi_2 = interval_2[1]
    range_1 = hi_1 - lo_1 + 1
    range_2 = hi_2 - lo_2 + 1
    pos_1 = x - lo_1

    base_val = pos_1 + lo_2
    y = range(base_val, hi_2+1, range_1)


    return y

def alg_2(y, interval_1, interval_2):
# Map Y, an element of interval 2,
#   to its corresponding element in interval1.

    lo_1 = interval_1[0]
    hi_1 = interval_1[1]
    lo_2 = interval_2[0]
    hi_2 = interval_2[1]
    range_1 = hi_1 - lo_1 + 1
    range_2 = hi_2 - lo_2 + 1
    pos_2 = y - lo_2

    x = lo_1 + pos_2 % range_1

    return x


i1 = (2, 5)
i2 = (4, 13)

print "X  Y"

for val in range(i1[0], i1[1]+1):
    print val, alg_1(val, i1, i2)

print ""
print "Y  X"

for val in range(i2[0], i2[1]+1):
    print val, alg_2(val, i1, i2)

输出:

X  Y
2 [4, 8, 12]
3 [5, 9, 13]
4 [6, 10]
5 [7, 11]


Y  X
4 2
5 3
6 4
7 5
8 2
9 3
10 4
11 5
12 2
13 3

<强>问题 对于X =&gt; Y映射,此方法返回映射值列表。此列表的大小为|i2| / |i1|。那可以接受吗?当这个比率上升到大约2 ^ 25时,它会变慢。

如果您愿意,可以返回 xrange 而不是范围;这是序列的生成器,而不是序列本身。

答案 1 :(得分:1)

您可以使用multiplicative inverse和偏移量轻松完成此操作。首先减去A.然后进行乘法逆计算,并通过添加C来翻译结果。

要反转它,减去D,执行乘法逆计算的反函数,然后添加A.

这很有效。我过去使用它效果很好。