【问题标题】:Given two strings, how do I find number of reoccurences of one in another?给定两个字符串,我如何找到一个在另一个中出现的次数?
【发布时间】:2014-12-05 19:00:20
【问题描述】:

例如,s1='abc's2='kokoabckokabckoab'。 输出应为3。 (s1 在 s2 中出现的次数)。

不允许使用forstrfind只能使用reshape,repmat,size

我想重塑 s2,让它包含所有可能的 3 字符串:

s2 =

好的

koa

oab

....等

但是我从这里遇到了麻烦..

【问题讨论】:

  • 只是为了确定:上面 s2 的末尾是否缺少“c”? (所以输出是3)
  • ismember 呢?
  • 我们可以使用sum吗?我可以确定一个解决方案,但它也需要sum。顺便说一句,你的 MATLAB 导师还是很烂。

标签: string matlab


【解决方案1】:

假设您将矩阵重整为帖子中的格式,您可以复制 s1 并堆叠字符串,使其具有与重整后的 s2 矩阵中的行数一样多的行,然后执行相等操作员。由全 1 组成的行意味着我们找到了匹配项,因此您只需搜索总和等于 s1 总长度的那些行。参考back to my post on dividing up a string into overlapping substrings,我们可以将您的字符串分解为您在问题中发布的内容,如下所示:

%// Define s1 and s2 here
s1 = 'abc';
len = length(s1);
s2 = 'kokoabckokabckoab'; 

%// Hankel starts here
c = (1 : len).'; 
r = (len : length(s2)).';
nr = length(r);
nc = length(c);

x = [ c; r((2:nr)') ];          %-- build vector of user data

cidx = (1:nc)';
ridx = 0:(nr-1);
H = cidx(:,ones(nr,1)) + ridx(ones(nc,1),:);  % Hankel subscripts
ind = x(H);                            % actual data
%// End Hankel script

%// Now get our data
subseqs = s2(ind.');

%// Case where string length is 1
if len == 1
    subseqs = subseqs.';
end

subseqs 包含您在帖子中提到的重叠字符矩阵。您已经注意到一个小错误,如果字符串的长度为 1,那么算法将不起作用。您需要确保重构的子字符串矩阵由单个 column 向量组成。如果我们在不检查s1 的长度的情况下运行上述代码,我们会得到一个行向量,如果是这种情况,只需转置结果即可。

现在,只需复制s1 的次数与我们在subseqs 中的行数一样多,这样所有这些字符串都会堆叠成一个二维矩阵。之后,做一个相等运算符。

eqs = subseqs == repmat(s1, size(subseqs,1), 1);

现在,找到按列的总和,看看哪些元素等于字符串的长度。这将产生一个单列向量,其中1 表示我们找到了匹配项,否则为零:

sum(eqs, 2) == len

ans =

     0
     0
     0
     0
     1
     0
     0
     0
     0
     0
     1
     0
     0
     0
     0

最后,要将子字符串匹配的多少次相加,您只需将此向量中的所有元素相加即可:

out = sum(sum(eqs, 2) == len)

out = 

2

因此,我们有 两个 在您的字符串中找到 abc 的实例。

【讨论】:

  • 非常好,你无中生有的回答了! ismember 使它更容易,但可能是不允许的。 +1
  • 如果s1的长度为1会怎样?
  • @Osh24 - 好点。如果是这种情况,我需要确保 subseqs 是一个列向量。一旦你这样做了,算法就会起作用。
  • @rayryeng 立即清除!谢谢:)
  • 我喜欢这个解决方案,因为它适用于任何字符串大小。 +1
【解决方案2】:

这是另一个,

s1='abc'; 
s2='bkcokbacaabcsoabckokabckoabc';

[a,b] = ismember(s2,s1);
b = [0 0 b 0 0];
a1=circshift(b,[0 -1]);
a2=circshift(b,[0 -2]);
sum((b==1)&(a1==2)&(a2==3))

它为您的输入提供3,在我的示例中提供4,如果ismember 没问题,它似乎工作得很好。

【讨论】:

  • 如果ismembercircshift 被允许,我也会这样做:) +1。
  • 不错的方法。我唯一的抱怨是该代码仅对固定大小的s1 有效(在本例中为 3)。 +1
【解决方案3】:

只是为了好玩:这可以通过图像处理工具箱中的nlfilter 来完成(我今天刚刚发现了这个功能,很想应用它!):

ds1 = double(s1);
ds2 = double(s2);
result = sum(nlfilter(ds2, [1 numel(ds1)], @(x) all(x==ds1)));

【讨论】:

  • 是的,你是对的,我的回答确实有这个缺点,我没有意识到,这是非常好的 BTW +1,
  • 哦,你找到了 :)。我也用它来回答我的一堆问题。不错!
  • 我今天在 Divakar 的回答中看到了这一点。可惜我在你的答案中错过了它!但是,既然我是第一次使用该功能,我发现它可能是一个缓慢的功能。在我的 Matlab 版本上,它甚至(短暂)显示一个等待栏
  • @rayryeng 感谢您的编辑!我猜我第一次使用nlfilter 时的情绪蒙蔽了我的视线:-D
  • @LuisMendo - 有一些快捷方式取决于你想如何使用nlfilter。例如,如果要查找图像像素邻域的局部最大值,请使用imdilate,对于局部最小值,请使用imerode。形态例程比nlfilter 更有效,因为nlfilter 用于更一般的非线性过滤,而形态过滤器针对特定任务进行了调整。无论哪种方式,很高兴看到你使用它!
猜你喜欢
  • 2013-05-07
  • 1970-01-01
  • 2017-07-26
  • 1970-01-01
  • 1970-01-01
  • 2014-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多