如何让我的代码更快?

时间:2015-02-02 12:45:39

标签: performance matlab

我编写这段代码来解决问题4项目的euler,但是给我答案需要很长时间。

有什么技巧可以让它更快吗?

function S=Problem4(n)
tic
Interval=10^(n-1):10^(n)-1;
[Product1,Product2]=meshgrid(Interval);
Func=@(X,Y) X*Y;
Temp=cell2mat(arrayfun(Func,Product1,Product2,'UniformOutput',false));
Palindrome=@(X) all(num2str(X)==fliplr(num2str(X)));
Temp2=unique(Temp(:));
S=max(Temp2(arrayfun(Palindrome,Temp2)));
toc
end

并且大约需要39秒。

任何帮助都将不胜感激。

4 个答案:

答案 0 :(得分:2)

来自Project Euler

  

最大的回文产品
  问题4

     

回文数字两种方式相同。由两个2位数字的乘积制成的最大回文是9009 = 91×99。

     

找出由两个3位数字的乘积制成的最大回文。

我会给你另一种方法,而不是分析你的代码,你可能会发现它很有用。它利用了矢量化,避免了arrayfun和匿名函数,这可能很慢:

[n1, n2] = ndgrid(100:999); %// all combinations of 3-digit numbers
pr = n1(:).*n2(:); %// product of each combination
de = dec2base(pr, 10); %// decimal expression of those products
sm = pr<1e5; %// these have 5 figures: initial digit "0" should be disregarded
pa = false(1,numel(pr)); %// this will indicate if each product is palindromic or not
pa(sm) = all(de(sm,2:end) == fliplr(de(sm,2:end)), 2); %// 5-figure palindromic
pa(~sm) = all(de(~sm,:) == fliplr(de(~sm,:)), 2); %// 6-figure palindromic
result = max(pr(pa)); %// find maximum among all products indicated by pa

通过避免重复产品,您可以节省近一半的时间,如下所示。标记了三个新行:

[n1, n2] = ndgrid(100:999); %// all combinations of 3-digit numbers
un = n1(:)<=n2(:); %// NEW
n1 = n1(un); %//       NEW
n2 = n2(un); %//       NEW
pr = n1(:).*n2(:); %// product of each combination
de = dec2base(pr, 10); %// decimal expression of those products
sm = pr<1e5; %// these have 5 figures: initial digit "0" should be disregarded
pa = false(1,numel(pr)); %// this will indicate if each product is palindromic or not
pa(sm) = all(de(sm,2:end) == fliplr(de(sm,2:end)), 2); %// 5-figure palindromic
pa(~sm) = all(de(~sm,:) == fliplr(de(~sm,:)), 2); %// 6-figure palindromic
result = max(pr(pa)); %// find maximum among all products indicated by pa

答案 1 :(得分:2)

这里只是部分答案,但通常会因使用字符串处理数字而导致性能大打击。

在这里你有一个功能,甚至可以在一行中完成两次!

首先尝试通过将中间结果保存在变量中来消除一个。如果这可以节省大量时间,那么也可能值得删除另一个。


这是几年前我自己的做法。它不是那么好,但也许它可以激励你。

请注意,它确实使用num2str,但只使用一次,并且同时使用所有相关数字。在您的代码中,您使用的arrayfun基本上在内部使用了一个循环,可能会导致多次调用num2str

clear
field = (100:999)'*(100:999);
field = field(:);
fieldstr = num2str(field);
idx = fieldstr(:,1) == fieldstr(:,end);
idx2 = fieldstr(:,2) == fieldstr(:,end-1);
idx3 = fieldstr(:,3) == fieldstr(:,end-2);
list = fieldstr(idx & idx2 & idx3,:);
listnum = str2num(list);
max(listnum)

答案 2 :(得分:1)

一些讨论和解决方案代码

由于您正在寻找maximum回文,因为您使用Interval收集了可能的产品编号number of digits all the numbers你可以迭代地寻找最大可能的数字。因此,使用n = 3,您可以从10000998001作为产品。因此,您可以先查找6 digit个数字中的最大回文数,然后选择5 digits个,依此类推。这种迭代方法的好处是,只要您拥有get out号码,就可以 max 。这是履行讨论中承诺的代码 -

function S = problem4_try1(n)

Interval=10^(n-1):10^(n)-1; %// Define interval definition here

prods = bsxfun(@times,Interval,Interval'); %//'# Or Use: Interval'*Interval
allnums = prods(:);

numd = ceil(log10(allnums));        %// number of digits
dig = sort(unique(numd),'descend'); %// unique digits starting from highest one

for iter = 1:numel(dig)
    numd_iter = dig(iter);
    numd_iter_halflen = floor(numd_iter/2);

    all_crit = allnums(numd==numd_iter); %//all numbers in current iteration
    all_crit_dg = dec2base(all_crit,10)-'0'; %// separate digits for a 2D array

    all_curit_digits_pal = all_crit(all(all_crit_dg(:,1:numd_iter_halflen) == ...
        all_crit_dg(:,end:-1:end-numd_iter_halflen+1) ,2)); %// palindrome matches

    %// Find the max of palindrom matches and get out
    if ~isempty(all_curit_digits_pal)
        S = max(all_curit_digits_pal);
        return;                         %//  *** Get Outta Here!!
    end
end

关于代码本身的一些事情

  1. bsxfun(@times,Interval,Interval')有效地为我们提供了Temp中的产品值,因此这必须非常高效,因为不必处理中间Product1和{ {1}}。
  2. 由于迭代性质,它必须足够高效Product2,因为系统可以在开始时处理产品计算的预处理部分。

答案 3 :(得分:-4)

我鼓励你看到这个链接(improving matlab performance),我建议你使用“缓存/内存”功能,当你进行迭代计算时,你可以存储参数和答案,这样下次你有了相同的参数,你只需返回存储的答案,跳过过程中的一些计算。

希望它有所帮助,告诉我你是否有更多的怀疑。