使用递归求解q中的Euler 18

时间:2019-02-25 18:20:18

标签: kdb

我已经在q中编写了此代码,以使用递归解决下面的链接中所述的Euler 18问题。

https://stackoverflow.com/questions/8002252/euler-project-18-approach

尽管代码可以正常工作,但效率不高,并且在金字塔大小大于3000的金字塔上会出现堆栈溢出。我如何才能使代码效率更高。我认为最佳代码可以少于30个字符。

pyr:{[x]
    lsize:count x;
    y:x;
    $[lsize <=1;y[0];
    [.ds.lastone:x[lsize - 1];
    .ds.lasttwo:x[lsize - 2];
    y:{{max (.ds.lasttwo)[x] +/: .ds.lastone[x],.ds.lastone[x+1]}each til count .ds.lasttwo};
    $[(count .ds.lasttwo)=1;y:{max (.ds.lasttwo) +/: .ds.lastone[x],.ds.lastone[x+1]}0;y:y[]];
    x[lsize - 2]:y;
    pyr[-1_x]]]
 }

1 个答案:

答案 0 :(得分:4)

要在q中正确实现此逻辑,您需要使用副词。

首先,要快速找到滚动最大值,可以使用prior副词。例如:

q)input:(75;95 64;17 47 82;18 35 87 10;20 04 82 47 65;19 01 23 75 03 34;88 02 77 73 07 63 67;99 65 04 28 06 16 70 92;41 41 26 56 83 40 80 70 33;41 48 72 33 47 32 37 16 94 29;53 71 44 65 25 43 91 52 97 51 14;70 11 33 28 77 73 17 78 39 68 17 57;91 71 52 38 17 14 91 43 58 50 27 29 48;63 66 04 68 89 53 67 30 73 16 69 87 40 31;04 62 98 27 23 09 70 98 73 93 38 53 60 04 23)
q)last input
4 62 98 27 23 9 70 98 73 93 38 53 60 4 23
q)1_(|) prior last input
62 98 98 27 23 70 98 98 93 93 53 60 60 23

最后一行输出一个向量,该向量在输入向量的每个连续对之间具有最大值。一旦有了它,您可以将其添加到下一行并重复。

q)foo:{y+1_(|) prior x}
q)foo[input 14;input 13]
125 164 102 95 112 123 165 128 166 109 122 147 100 54

然后,使用over副词在整个函数中应用此功能:

q)foo over reverse input
,1074

编辑:以上方法可以进一步推广。

q提供了最大运动函数mmax。有了这个,您可以找到“数字y的x个项目的移动最大值”,它概括了上面prior的用法。例如,您可以使用它在输入的最后一行中查找成对或 triplet 的最大移动量:

q)last input
4 62 98 27 23 9 70 98 73 93 38 53 60 4 23
q)2 mmax last input
4 62 98 98 27 23 70 98 98 93 93 53 60 60 23
q)3 mmax last input
4 62 98 98 98 27 70 98 98 98 93 93 60 60 60

mmax可用于简化上面的foo

q)foo:{y+1_ 2 mmax x}

关于此的特别好之处在于,它可以用于推广使用更宽的三角形来解决此问题。例如,下面的三角形在每行上都有两个以上的值,并且您可以从行的任何一点向其下方的行的左侧,中间或右侧移动。

    5
  5 6 7
6 7 3 9 1