【问题标题】:Create a "pyramid" matrix创建一个“金字塔”矩阵
【发布时间】:2015-11-17 11:48:23
【问题描述】:

假设我得到一个奇数长度的对称行向量,其中每个元素小于向量前半部分的下一个元素,每个元素都大于后半部分的下一个元素,中间元素是最大的。 (例如[1 2 3 2 1][10 20 50 20 10])。

我想创建一个方阵,其中该行向量是它的中间行,等效的列向量 (v') 是它的中间列,并且每个其他行或列是给定向量的缩减版本根据中间此行或列中的元素。当没有更多“原始元素”时,我们输入0

例子:

如果v = [1 2 3 2 1] 我们得到

0 0 1 0 0  
0 1 2 1 0  
1 2 3 2 1  
0 1 2 1 0  
0 0 1 0 0

如果v = [3 5 3] 我们得到

0 3 0  
3 5 3  
0 3 0  

到目前为止我所做的:我设法创建了一个矩阵,其中 v 作为中间行,v' 作为中间列,并使用我编写的这段代码:

s = length(vector);
matrix= zeros(s);
matrix(round(s/2),:) = vector;
matrix(:, round(s/2)) = vector';

但在分配其他值时遇到了困难。

【问题讨论】:

    标签: arrays matlab matrix


    【解决方案1】:

    更实用的方法是将矩阵生成为马赛克,从hankel 矩阵开始。为了性能对比,这里有一个与@Divakar's solution格式相同的版本:

    function out=pyramid_hankel(v)
    
    %I suggest checking v here
    %it should be odd in length and a palindrome    
    
    i0=ceil(length(v)/2);
    v2=v(i0:end);
    
    Mtmp=hankel(v2);
    out=zeros(length(v));
    out(i0:end,i0:end)=Mtmp;
    out(1:i0-1,i0:end)=flipud(Mtmp(2:end,:));
    out(:,1:i0-1)=fliplr(out(:,i0+1:end));
    
    >> pyramid_hankel([1 2 3 2 1])
    
    ans =
    
         0     0     1     0     0
         0     1     2     1     0
         1     2     3     2     1
         0     1     2     1     0
         0     0     1     0     0
    

    对于v=[1 2 3 2 1],起始块是hankel([3 2 1]),即

    ans =
    
         3     2     1
         2     1     0
         1     0     0
    

    从这里应该清楚发生了什么。

    【讨论】:

    • @Adrian 和@AndrasDeak:hankel 函数在内部使用bsxfun
    • 哦,不要!我使用bsxfun 的方式与使用bsxfun. 实现hankel 的方式不同@AFAIK hankel 有bsxfun(@plus
    【解决方案2】:

    这是一种方法 -

    function out = pyramid(v)
    
    hlen = (numel(v)+1)/2;
    updown_vec = [1:(numel(v)+1)/2 (numel(v)-1)/2:-1:1];
    upper_part = cumsum(bsxfun(@le,(hlen:-1:1)',updown_vec));  %//'
    out = [upper_part ; flipud(upper_part(1:end-1,:))];
    out = changem(out,v,updown_vec);
    

    这是另一种方法,可能更简单 -

    function out = pyramid_v2(v)
    
    hlen = (numel(v)+1)/2;
    updown_vec = [1:(numel(v)+1)/2 (numel(v)-1)/2:-1:1];
    mask = bsxfun(@le,([hlen:-1:1 2:hlen])',updown_vec); %//'
    M = double(mask);
    M(hlen+1:end,:) = -1;
    out = changem(cumsum(M).*mask,v,updown_vec);
    

    示例运行 -

    >> v = [1 2 3 2 1];
    >> pyramid(v)
    ans =
         0     0     1     0     0
         0     1     2     1     0
         1     2     3     2     1
         0     1     2     1     0
         0     0     1     0     0
    >> v = [3 5 3];
    >> pyramid(v)
    ans =
         0     3     0
         3     5     3
         0     3     0
    
    >> v = [99,3,78,55,78,3,99];
    >> pyramid(v)
    ans =
         0     0     0    99     0     0     0
         0     0    99     3    99     0     0
         0    99     3    78     3    99     0
        99     3    78    55    78     3    99
         0    99     3    78     3    99     0
         0     0    99     3    99     0     0
         0     0     0    99     0     0     0
    

    【讨论】:

    • 虽然我的回答似乎更容易接受,但您是否希望在处理大问题时更快?
    • 出于好奇,我检查了你的两种计算速度的方法:@AndrasDeak - 0.055571;迪瓦卡 - 0.03777。但是伙计们!您的思维速度快要杀死我了-我看到了这个问题,并且已经为所有必要的对角线计算了公式,并尝试实施它,揉着我的手掌……而且您已经发布了答案,这使我无法理解它的优雅。我仍然无法开始以矩阵形式而不是循环形式思考:)
    • @Mikhail_Sam 感谢基准测试的努力!所以,你测试的那个是_v2 那个,对吧?感谢您的赞赏:)
    • @AndrasDeak 我希望 version-2 更快,因为它更简单一些,并且避免了 flipud 并因此附加。
    • 感谢@Mikhail_Sam 的反馈!:) 正是我想知道的。我对 Divakar 的速度更快并不感到惊讶,我只是因为偷了接受而感到有点难过:P Mikhail:对于它的价值,如果我没有找到 hankel,我就不会尝试回答它。我意识到如果没有必要的内置功能,Divakar 会用bsxfun 击败我;)
    【解决方案3】:

    这是另一种方法:

    v = [1 2 3 2 1]; %// symmetric, odd size
    m = (numel(v)-1)/2;
    w = [0 v(1:m+1)];
    t = abs(-m:m);
    result = w(max(m+2-bsxfun(@plus, t, t.'),1));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多