不知道这是否有帮助,但这是另一种解决方案:
int lexic_ix(int* A, int n){ //n = last index = number of digits - 1
int value = 0;
int x = 0;
for(int i=0 ; i<n ; i++){
int diff = (A[i] - x); //pb1
if(diff > 0)
{
for(int j=0 ; j<i ; j++)//pb2
{
if(A[j]<A[i] && A[j] > x)
{
if(A[j]==x+1)
{
x++;
}
diff--;
}
}
value += diff;
}
else
{
x++;
}
value *= n - i;
}
return value;
}
我无法摆脱内部循环,因此在最坏的情况下复杂度为 o(n log(n)),但在最好的情况下为 o(n),而您的解决方案总共为 o(n log(n))案例。
或者,您可以通过以下方式替换内部循环,以消除一些最坏的情况,但代价是内部循环中的另一个验证:
int j=0;
while(diff>1 && j<i)
{
if(A[j]<A[i])
{
if(A[j]==x+1)
{
x++;
}
diff--;
}
j++;
}
说明:
(或者更确切地说“我是如何用那个代码结束的”,我认为它与你的没有什么不同,但它可以让你有想法,也许)(为了减少混淆,我使用字符而不是数字和只有四个字符)
abcd 0 = ((0 * 3 + 0) * 2 + 0) * 1 + 0
abdc 1 = ((0 * 3 + 0) * 2 + 1) * 1 + 0
acbd 2 = ((0 * 3 + 1) * 2 + 0) * 1 + 0
acdb 3 = ((0 * 3 + 1) * 2 + 1) * 1 + 0
adbc 4 = ((0 * 3 + 2) * 2 + 0) * 1 + 0
adcb 5 = ((0 * 3 + 2) * 2 + 1) * 1 + 0 //pb1
bacd 6 = ((1 * 3 + 0) * 2 + 0) * 1 + 0
badc 7 = ((1 * 3 + 0) * 2 + 1) * 1 + 0
bcad 8 = ((1 * 3 + 1) * 2 + 0) * 1 + 0 //First reflexion
bcda 9 = ((1 * 3 + 1) * 2 + 1) * 1 + 0
bdac 10 = ((1 * 3 + 2) * 2 + 0) * 1 + 0
bdca 11 = ((1 * 3 + 2) * 2 + 1) * 1 + 0
cabd 12 = ((2 * 3 + 0) * 2 + 0) * 1 + 0
cadb 13 = ((2 * 3 + 0) * 2 + 1) * 1 + 0
cbad 14 = ((2 * 3 + 1) * 2 + 0) * 1 + 0
cbda 15 = ((2 * 3 + 1) * 2 + 1) * 1 + 0 //pb2
cdab 16 = ((2 * 3 + 2) * 2 + 0) * 1 + 0
cdba 17 = ((2 * 3 + 2) * 2 + 1) * 1 + 0
[...]
dcba 23 = ((3 * 3 + 2) * 2 + 1) * 1 + 0
第一个“反思”:
熵的观点。abcd 的“熵”最少。如果一个角色在一个它“不应该”的地方,它就会产生熵,而熵越早变得最大。
例如,对于 bcad,词典索引为 8 = (( 1 * 3 + 1 ) * 2 + 0 ) * 1 + 0并且可以这样计算:
value = 0;
value += max(b - a, 0); // = 1; (a "should be" in the first place [to create the less possible entropy] but instead it is b)
value *= 3 - 0; //last index - current index
value += max(c - b, 0); // = 1; (b "should be" in the second place but instead it is c)
value *= 3 - 1;
value += max(a - c, 0); // = 0; (a "should have been" put earlier, so it does not create entropy to put it there)
value *= 3 - 2;
value += max(d - d, 0); // = 0;
请注意,最后一个操作总是什么都不做,这就是为什么“i
第一个问题(pb1):
例如,对于 adcb,第一个逻辑不起作用(它导致 ((0* 3+ 2) * 2+ 0) * 1 = 4 的字典索引),因为 cd = 0 但它会创建熵来放置 c在 b 之前 因此,我添加了 x,它表示尚未放置的第一个数字/字符。对于 x,diff 不能为负数。对于 adcb,词典索引是 5 = (( 0 * 3 + 2 ) * 2 + 1 ) * 1 + 0 并且可以这样计算:
value = 0; x=0;
diff = a - a; // = 0; (a is in the right place)
diff == 0 => x++; //x=b now and we don't modify value
value *= 3 - 0; //last index - current index
diff = d - b; // = 2; (b "should be" there (it's x) but instead it is d)
diff > 0 => value += diff; //we add diff to value and we don't modify x
diff = c - b; // = 1; (b "should be" there but instead it is c) This is where it differs from the first reflexion
diff > 0 => value += diff;
value *= 3 - 2;
第二个问题(pb2):
例如,对于 cbda,词典索引是 15 = ((2 * 3 + 1) * 2 + 1) * 1 + 0,但第一个反射给出:((2 * 3 + 0) * 2 + 1) * 1 + 0 = 13 并且 pb1 的解决方案给出 ((2 * 3 + 1) * 2 + 3) * 1 + 0 = 17。pb1 的解决方案不起作用,因为要放置的最后两个字符是 d 和 a,所以 d - “意味着” 1 而不是 3。我必须计算在该字符之前放置的字符,但在 x 之后,所以我必须添加一个内部循环。
把它们放在一起:
然后我意识到 pb1 只是 pb2 的一个特例,如果你删除 x,并且你只取 diff = A[i],我们最终会得到你的解决方案的未嵌套版本(逐步计算阶乘,并且我的差异对应于你的 x)。
所以,基本上,我的“贡献”(我认为)是添加一个变量 x,它可以避免在 diff 等于 0 或 1 时执行内部循环,但代价是检查是否必须增加 x 并在需要时执行.
我还检查了是否必须在内部循环中增加 x (if(A[j]==x+1)),因为如果以 badce 为例,x 最后将是 b,因为 a 在 b 之后,而你将再次进入内循环,遇到c。如果在内循环中检查x,当遇到d时只能做内循环,但是x会更新为c,遇到c时不会进入内循环。您可以在不破坏程序的情况下删除此检查
使用替代版本和内部循环中的检查,它产生了 4 个不同的版本。带有检查的替代方法是您输入的内部循环越少,因此就“理论复杂性”而言,它是最好的,但就性能/操作数量而言,我不知道。
希望所有这些都有帮助(因为这个问题相当老了,而且我没有详细阅读所有答案)。如果没有,我仍然玩得很开心。对不起,很长的帖子。另外,我是 Stack Overflow 上的新手(作为成员),而不是母语人士,所以请保持友善,如果我做错了什么,请随时告诉我。