- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
几天前我玩弄了Befunge这是一种深奥的编程语言。 Befunge 使用 LIFO 堆栈来存储数据。当您编写程序时,从 0 到 9 的数字实际上是将相应值压入堆栈的 Befunge 指令。因此,例如,这会将 7 压入堆栈:
34+
为了压入大于 9 的数字,必须对小于或等于 9 的数字进行计算。这将产生 123。
99*76*+
同时解决Euler Problem 1对于 Befunge,我不得不将相当大的数字 999 压入堆栈。在这里,我开始想知道如何用尽可能少的指令完成这项任务。通过用中缀符号写下一个术语并取出我想出的共同因素
9993+*3+*
也可以简单地将两个两位数相乘得到 999,例如
39*66*1+*
我考虑了一会儿,然后决定编写一个程序,根据这些规则以反向波兰表示法为任何给定的整数输出最小的表达式。这是我目前所拥有的(用 NodeJS 和 underscorejs 编写):
var makeExpr = function (value) {
if (value < 10) return value + "";
var output = "", counter = 0;
(function fn (val) {
counter++;
if(val < 9) { output += val; return; };
var exp = Math.floor(Math.log(val) / Math.log(9));
var div = Math.floor(val / Math.pow(9, exp));
_( exp ).times(function () { output += "9"; });
_(exp-1).times(function () { output += "*"; });
if (div > 1) output += div + "*";
fn(val - Math.pow(9, exp) * div);
})(value);
_(counter-1).times(function () { output+= "+"; });
return output.replace(/0\+/, "");
};
makeExpr(999);
// yields 999**99*3*93*++
这段代码天真地构造了表达式,显然太长了。现在我的问题:
9993+*3+*
这样的表达式是可能的最小表达式?希望大家多多指教。提前致谢。
最佳答案
当只考虑乘法和加法时,很容易构造最优公式,因为该问题具有最优子结构性质。即构建[num1][num2]op
的最优方式来自num1
和 num2
这也是最佳的。如果还考虑重复,那就不再正确了。
num1
和 num2
产生重叠的子问题,因此适用动态规划。
我们可以简单地,对于一个数字i
:
1 < j <= sqrt(i)
平均划分 i
, 尝试 [j][i / j]*
0 < j < i/2
, 尝试 [j][i - j]+
这当然很容易自下而上,只需从 i = 0
开始并努力达到您想要的任何数字。不幸的是,第 2 步有点慢,所以在说 100000 之后等待它开始变得烦人。可能有一些我没有看到的技巧。
C# 中的代码(没有经过很好的测试,但它似乎可以工作):
string[] n = new string[10000];
for (int i = 0; i < 10; i++)
n[i] = "" + i;
for (int i = 10; i < n.Length; i++)
{
int bestlen = int.MaxValue;
string best = null;
// try factors
int sqrt = (int)Math.Sqrt(i);
for (int j = 2; j <= sqrt; j++)
{
if (i % j == 0)
{
int len = n[j].Length + n[i / j].Length + 1;
if (len < bestlen)
{
bestlen = len;
best = n[j] + n[i / j] + "*";
}
}
}
// try sums
for (int j = 1; j < i / 2; j++)
{
int len = n[j].Length + n[i - j].Length + 1;
if (len < bestlen)
{
bestlen = len;
best = n[j] + n[i - j] + "+";
}
}
n[i] = best;
}
这里有一个优化总和搜索的技巧。假设有一个数组,其中包含对于每个长度,可以用该长度组成的最大数字。该数组还为我们提供的另一件事可能不太明显,是一种快速确定大于某个阈值的最短数字的方法(通过简单地扫描数组并注意超过阈值的第一个位置)。总之,这提供了一种快速丢弃大部分搜索空间的方法。
例如,长度为 3 的最大数是 81,长度为 5 的最大数是 728。现在如果我们想知道如何得到 1009(素数,所以没有找到因子),首先我们尝试求和,其中第一部分的长度为 1(所以 1+1008
到 9+1000
),找到 9+1000
长度为 9 个字符 ( 95558***+
)。
下一步,检查第一部分长度为 3 或更小的总和,可以完全跳过。 1009 - 81 = 929
, 和 929(如果第一部分为 3 个字符或更少,则总和的第二部分的最小值)大于 728,因此 929 及以上的数字必须至少有 7 个字符长。所以如果总和的第一部分是3个字符,那么第二部分至少要7个字符,最后还要加一个+号,所以总共至少是11个字符。到目前为止最好的是 9,所以可以跳过这一步。
下一步,第一部分有5个字符,也可以跳过,因为1009 - 728 = 280
, 要达到 280 或更高,我们至少需要 5 个字符。 5 + 5 + 1 = 11
, 大于 9,所以不检查。
用这种方法我们只需要检查 9 个,而不是检查大约 500 个和,而且使跳过成为可能的检查非常快。这个技巧非常好,在我的 PC 上只需要 3 秒就可以生成一百万以内的所有数字(以前,生成 100000 需要 3 秒)。
代码如下:
string[] n = new string[100000];
int[] biggest_number_of_length = new int[n.Length];
for (int i = 0; i < 10; i++)
n[i] = "" + i;
biggest_number_of_length[1] = 9;
for (int i = 10; i < n.Length; i++)
{
int bestlen = int.MaxValue;
string best = null;
// try factors
int sqrt = (int)Math.Sqrt(i);
for (int j = 2; j <= sqrt; j++)
{
if (i % j == 0)
{
int len = n[j].Length + n[i / j].Length + 1;
if (len < bestlen)
{
bestlen = len;
best = n[j] + n[i / j] + "*";
}
}
}
// try sums
for (int x = 1; x < bestlen; x += 2)
{
int find = i - biggest_number_of_length[x];
int min = int.MaxValue;
// find the shortest number that is >= (i - biggest_number_of_length[x])
for (int k = 1; k < biggest_number_of_length.Length; k += 2)
{
if (biggest_number_of_length[k] >= find)
{
min = k;
break;
}
}
// if that number wasn't small enough, it's not worth looking in that range
if (min + x + 1 < bestlen)
{
// range [find .. i] isn't optimal
for (int j = find; j < i; j++)
{
int len = n[i - j].Length + n[j].Length + 1;
if (len < bestlen)
{
bestlen = len;
best = n[i - j] + n[j] + "+";
}
}
}
}
// found
n[i] = best;
biggest_number_of_length[bestlen] = i;
}
还有改进的余地。此代码将重新检查它已经检查过的总和。有一些简单的方法可以让它至少不检查相同的总和两次(通过记住最后一个 find
),但这在我的测试中没有显着差异。应该可以找到一个更好的上限。
关于algorithm - 逆波兰表示法的简化算法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20153412/
我在一本书(Interview Question)中读到这个问题,想在这里详细讨论这个问题。请点亮它。 问题如下:- 隐私和匿名化 马萨诸塞州集团保险委员会早在 1990 年代中期就有一个绝妙的主意
我最近接受了一次面试,面试官给了我一些伪代码并提出了相关问题。不幸的是,由于准备不足,我无法回答他的问题。由于时间关系,我无法向他请教该问题的解决方案。如果有人可以指导我并帮助我理解问题,以便我可以改
这是我的代码 public int getDist(Node root, int value) { if (root == null && value !=0) return
就效率而言,Strassen 算法应该停止递归并应用乘法的最佳交叉点是多少? 我知道这与具体的实现和硬件密切相关,但对于一般情况应该有某种指南或某人的一些实验结果。 在网上搜索了一下,问了一些他们认为
我想学习一些关于分布式算法的知识,所以我正在寻找任何书籍推荐。我对理论书籍更感兴趣,因为实现只是个人喜好问题(我可能会使用 erlang(或 c#))。但另一方面,我不想对算法进行原始的数学分析。只是
我想知道你们中有多少人实现了计算机科学的“ classical algorithms ”,例如 Dijkstra's algorithm或现实世界中的数据结构(例如二叉搜索树),而不是学术项目? 当有
我正在解决旧编程竞赛中的一些示例问题。在这个问题中,我们得到了我们有多少调酒师以及他们知道哪些食谱的信息。制作每杯鸡尾酒需要 1 分钟,我们需要使用所有调酒师计算是否可以在 5 分钟内完成订单。 解决
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 8 年前。 Improve
我开始学习 Nodejs,但我被困在中间的某个地方。我从 npm 安装了一个新库,它是 express -jwt ,它在运行后显示某种错误。附上代码和错误日志,请帮助我! const jwt = re
我有一个证书,其中签名算法显示“sha256rsa”,但指纹算法显示“sha1”。我的证书 SHA1/SHA2 的标识是什么? 谢谢! 最佳答案 TL;TR:签名和指纹是完全不同的东西。对于证书的强度
我目前在我的大学学习数据结构类(class),并且在之前的类(class)中做过一些算法分析,但这是我在之前的类(class)中遇到的最困难的部分。我们现在将在我的数据结构类(class)中学习算法分
有一个由 N 个 1x1 方格组成的区域,并且该区域的所有部分都是相连的(没有任何方格无法到达的方格)。 下面是一些面积的例子。 我想在这个区域中选择一些方块,并且两个相邻的方块不能一起选择(对角接触
我有一些多边形形状的点列表,我想将其包含在我页面上的 Google map 中。 我已经从原始数据中删除了尽可能多的不必要的多边形,现在我剩下大约 12 个,但它们非常详细以至于导致了问题。现在我的文
我目前正在实现 Marching Squares用于计算等高线曲线,我对此处提到的位移位的使用有疑问 Compose the 4 bits at the corners of the cell to
我正在尝试针对给定算法的约束满足问题实现此递归回溯函数: function BACKTRACKING-SEARCH(csp) returns solution/failure return R
是否有包含反函数的库? 作为项目的一部分,我目前正在研究测向算法。我正在使用巴特利特相关性。在 Bartlett 相关性中,我需要将已经是 3 次矩阵乘法(包括 Hermitian 转置)的分子除以作
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎与 help center 中定义的范围内的编程无关。 . 关闭 8 年前。 Improve
问题的链接是UVA - 1394 : And There Was One . 朴素的算法是扫描整个数组并在每次迭代中标记第 k 个元素并在最后停止:这需要 O(n^2) 时间。 我搜索了一种替代算法并
COM 中创建 GUID 的函数 (CoCreateGUID) 使用“分散唯一性算法”,但我的问题是,它是什么? 谁能解释一下? 最佳答案 一种生成 ID 的方法,该 ID 具有一定的唯一性保证,而不
在做一个项目时我遇到了这个问题,我将在这个问题的实际领域之外重新措辞(我想我可以谈论烟花的口径和形状,但这会使理解更加复杂).我正在寻找一种(可能是近似的)算法来解决它。 我有 n 个不同大小的容器,
我是一名优秀的程序员,十分优秀!