非增加和非减少子序列的频率
Frequency of non-increasing and non-decreasing subsequences
有一个长度为 L
的数字序列,我需要计算有多少个精确长度的非递减和非递增子序列。例如,如果我有一个长度为 15
的序列
2, 4, 11, 13, 3, 5, 5, 6, 3, 3, 2, 4, 2, 14, 15
我看到非递增子序列是
13、3
6, 3, 3 , 2
4, 2
非递减子序列是
2、4、11、13
3、5、5、6
2, 4
2, 14, 15
所以我这里有
- 2个长度为2的非递增子序列
- 1个长度为4的非递增子序列
- 2个长度为2的非递减子序列
- 1个长度为3的非递减子序列
- 2个长度为4的非递减子序列
由于在这种情况下非递减(或非递增)子序列的最大长度可以是 15,因此我考虑通过向量 x 来表示非-增加和 y 对于非减少子序列:
x = (0,2,0,1,0,0,0,0,0,0,0,0,0,0,0)
y = (0,1,1,2,0,0,0,0,0,0,0,0,0,0,0)
将其扩展到长度为 L 的序列的一般情况,我想遍历该序列并使用循环计算精确长度的子序列的频率。我该怎么做?我会创建长度为 L 的零向量,每次遇到长度为 l[ 的子序列时,我都会将 1 添加到零矩阵的第 l 个元素=64=].
由于我的序列长度将是几千,我不会要求 Matlab 写它们,但我会要求它写我特定的频率。
这是一个好方法吗?
Matlab 中是否有一些函数可以执行此操作?
对于非递减序列:
x = [2, 4, 11,13,3,5,5,6,3,3,2,4,2,14,15]; %// data
y = [inf x -inf]; %// terminate data properly
starts = find(diff(y(1:end-1))<0 & diff(y(2:end))>=0);
ends = find(diff(y(1:end-1))>=0 & diff(y(2:end))<0);
result = histc(ends-starts+1, 1:numel(x));
对于非递增序列,只需改变 inf
的不等式和符号:
y = [-inf x inf]; %// terminate data properly
starts = find(diff(y(1:end-1))>0 & diff(y(2:end))<=0);
ends = find(diff(y(1:end-1))<=0 & diff(y(2:end))>0);
result = histc(ends-starts+1, 1:numel(x));
那个可爱的单行解决方案怎么样?
%// vector
A = [2, 4, 11, 13, 3, 5, 5, 6, 3, 3, 2, 4, 2, 14, 15]
%// number of digits in output
nout = 15;
seqFreq = @(vec,x) histc(accumarray(cumsum(~(-x*sign([x*1; diff(vec(:))]) + 1 )), ...
vec(:),[],@(x) numel(x)*~all(x == x(1)) ),1:nout).' %'
%// non-increasing sequences -> input +1
x = seqFreq(A,+1)
%// non-decreasing sequences -> input -1
y = seqFreq(A,-1)
x = 0 2 0 1 0 0 0 0 0 0 0 0 0 0 0
y = 0 1 1 2 0 0 0 0 0 0 0 0 0 0 0
说明
%// example for non-increasing
q = +1;
%// detect sequences: value = -1
seq = sign([q*1; diff(A(:))]);
%// find subs for accumarray
subs = cumsum(~(-q*seq + 1));
%// count number of elements and check if elements are equal, if not, set count to zero
counts = accumarray(subs,A(:),[],@(p) numel(p)*~all(p == p(1)) );
%// count number of sequences
x = histc(counts,1:nout);
有一个长度为 L
的数字序列,我需要计算有多少个精确长度的非递减和非递增子序列。例如,如果我有一个长度为 15
2, 4, 11, 13, 3, 5, 5, 6, 3, 3, 2, 4, 2, 14, 15
我看到非递增子序列是
13、3
6, 3, 3 , 2
4, 2
非递减子序列是
2、4、11、13
3、5、5、6
2, 4
2, 14, 15
所以我这里有
- 2个长度为2的非递增子序列
- 1个长度为4的非递增子序列
- 2个长度为2的非递减子序列
- 1个长度为3的非递减子序列
- 2个长度为4的非递减子序列
由于在这种情况下非递减(或非递增)子序列的最大长度可以是 15,因此我考虑通过向量 x 来表示非-增加和 y 对于非减少子序列:
x = (0,2,0,1,0,0,0,0,0,0,0,0,0,0,0)
y = (0,1,1,2,0,0,0,0,0,0,0,0,0,0,0)
将其扩展到长度为 L 的序列的一般情况,我想遍历该序列并使用循环计算精确长度的子序列的频率。我该怎么做?我会创建长度为 L 的零向量,每次遇到长度为 l[ 的子序列时,我都会将 1 添加到零矩阵的第 l 个元素=64=].
由于我的序列长度将是几千,我不会要求 Matlab 写它们,但我会要求它写我特定的频率。
这是一个好方法吗? Matlab 中是否有一些函数可以执行此操作?
对于非递减序列:
x = [2, 4, 11,13,3,5,5,6,3,3,2,4,2,14,15]; %// data
y = [inf x -inf]; %// terminate data properly
starts = find(diff(y(1:end-1))<0 & diff(y(2:end))>=0);
ends = find(diff(y(1:end-1))>=0 & diff(y(2:end))<0);
result = histc(ends-starts+1, 1:numel(x));
对于非递增序列,只需改变 inf
的不等式和符号:
y = [-inf x inf]; %// terminate data properly
starts = find(diff(y(1:end-1))>0 & diff(y(2:end))<=0);
ends = find(diff(y(1:end-1))<=0 & diff(y(2:end))>0);
result = histc(ends-starts+1, 1:numel(x));
那个可爱的单行解决方案怎么样?
%// vector
A = [2, 4, 11, 13, 3, 5, 5, 6, 3, 3, 2, 4, 2, 14, 15]
%// number of digits in output
nout = 15;
seqFreq = @(vec,x) histc(accumarray(cumsum(~(-x*sign([x*1; diff(vec(:))]) + 1 )), ...
vec(:),[],@(x) numel(x)*~all(x == x(1)) ),1:nout).' %'
%// non-increasing sequences -> input +1
x = seqFreq(A,+1)
%// non-decreasing sequences -> input -1
y = seqFreq(A,-1)
x = 0 2 0 1 0 0 0 0 0 0 0 0 0 0 0
y = 0 1 1 2 0 0 0 0 0 0 0 0 0 0 0
说明
%// example for non-increasing
q = +1;
%// detect sequences: value = -1
seq = sign([q*1; diff(A(:))]);
%// find subs for accumarray
subs = cumsum(~(-q*seq + 1));
%// count number of elements and check if elements are equal, if not, set count to zero
counts = accumarray(subs,A(:),[],@(p) numel(p)*~all(p == p(1)) );
%// count number of sequences
x = histc(counts,1:nout);