在字符串列表中查找相同位置的字符的算法?

时间:2008-09-16 01:50:34

标签: algorithm string

假设我有:

  1. 托比
  2. 微小
  3. 托里
  4. Tily
  5. 是否有一种算法可以轻松地在所有这些字符串中的相同位置创建常用字符列表? (在这种情况下,常见字符在位置0处为'T',在位置3处为'y')

    我尝试了一些用于DNA序列匹配的算法,但似乎大多数算法只是用于寻找常见的子串,而不管它们的位置如何。

8 个答案:

答案 0 :(得分:3)

查找某个位置的所有字符串中常见的字符列表非常简单。只需在每个字符位置迭代每个字符位置1个字符位置。如果任何字符串的字符与其最近邻居字符串的字符不匹配,则该位置不包含公共字符。

对于任何i = 0到长度-1 ...一旦找到Si [x]!= Si + 1 [x],您可以跳到下一个位置x + 1.

其中Si是列表中的第i个字符串。并且[x]是位置x处的字符。

答案 1 :(得分:1)

一些性能相当差的通用代码O(n ^ 2)

str[] = { "Toby", "Tiny", "Tory", "Tily" };
result = null;
largestString = str.getLargestString(); // Made up function
str.remove(largestString)
for (i = 0; i < largestString.length; i++) {
   hits = 0;
   foreach (str as value) {
      if (i < value.length) {
         if (value.charAt(i) == largestString.charAt(i))
            hits++;
      }
   }
   if (hits == str.length)
      result += largestString.charAt(i);
}
print(str.items);

答案 2 :(得分:1)

我无法想到任何特别优化的东西。

你可以做这样的事情,这不应该太难:

        //c# -- assuming your strings are in a List<string> named Names
        int shortestLength = Names[0].Length, j;
        char[] CommonCharacters;
        char single;

        for (int i = 1; i < Names.Count; i++)
        {
            if (Names[i].Length < shortestLength) shortestLength = Names[i].Length;
        }

        CommonCharacters = new char[shortestLength];
        for (int i = 0; i < shortestLength; i++)
        {
            j = 1;
            single = Names[0][i];
            CommonCharacters[i] = single;
            while (j < shortestLength)
            {
                if (single != Names[j][i])
                {
                    CommonCharacters[i] = " "[0];
                    break;
                }
                j++;
            }
        }

这将为您提供一系列与列表中所有内容相同的字符。

答案 3 :(得分:1)

这样的事情怎么样?

strings = %w(Tony Tiny Tory Tily)
positions = Hash.new { |h,k| h[k] = Hash.new { |h,k| h[k] = 0 } }
strings.each { |str| 
  0.upto(str.length-1) { |i| 
    positions[i][str[i,1]]+=1 
  }
}

执行结束时,结果将是:

positions = {
  0=>{"T"=>4},
  1=>{"o"=>2, "i"=>2}, 
  2=>{"l"=>1, "n"=>2, "r"=>1},
  3=>{"y"=>4}
}

答案 4 :(得分:1)

以下是5行红宝石的算法:

#!/usr/bin/env ruby
chars = STDIN.gets.chomp.split("")
STDIN.each do |string|
  chars = string.chomp.split("").zip(chars).map {|x,y| x == y ? x : nil }
end
chars.each_index {|i| puts "#{chars[i]}  #{i}" if chars[i] }

将它放在commonletters.rb中。样品用法:

$ commonletters.rb < input.txt
T  0
y  3

假设input.txt包含:

Toby
Tiny
Tory
Tily

这应该适用于您抛出的任何输入。如果输入文件为空,它将会中断,但您可以自己修复它。这是O(n)(n是输入中的字符总数)。

答案 5 :(得分:1)

这是Python中的一个简单版本:

items = ['Toby', 'Tiny', 'Tory', 'Tily']
tuples = sorted(x for item in items for x in enumerate(item))
print [x[0] for x in itertools.groupby(tuples) if len(list(x[1])) == len(items)]

打印哪些:

[(0, 'T'), (3, 'y')]

编辑:这是一个更好的版本,不需要创建(可能)庞大的元组列表:

items = ['Toby', 'Tiny', 'Tory', 'Tily']
minlen = min(len(x) for x in items)
print [(i, items[0][i]) for i in range(minlen) if all(x[i] == items[0][i] for x in items)]

答案 6 :(得分:1)

#include <iostream>

int main(void)
{
    char words[4][5] = 
    {
        "Toby",
        "Tiny",
        "Tory",
        "Tily"
    };

    int wordsCount = 4;
    int lettersPerWord = 4;

    int z;
    for (z = 1; z < wordsCount; z++)
    {
        int y;
        for (y = 0; y < lettersPerWord; y++)
        {
            if (words[0][y] != words[z][y])
            {
                words[0][y] = ' ';
            }
        }
    }

    std::cout << words[0] << std::endl;

    return 0;
}

答案 7 :(得分:0)

在lisp中:

CL-USER> (defun common-chars (&rest strings)
           (apply #'map 'list #'char= strings))
COMMON-CHARS

只需传入字符串:

CL-USER> (common-chars "Toby" "Tiny" "Tory" "Tily")
(T NIL NIL T)

如果您想要角色本身:

CL-USER> (defun common-chars2 (&rest strings)
           (apply #'map
                  'list
                  #'(lambda (&rest chars)
                      (when (apply #'char= chars)
                        (first chars))) ; return the char instead of T
                  strings))
COMMON-CHARS2

CL-USER> (common-chars2 "Toby" "Tiny" "Tory" "Tily")
(#\T NIL NIL #\y)

如果你不关心posiitons,只想要一个常见字符列表:

CL-USER> (format t "~{~@[~A ~]~}" (common-chars2 "Toby" "Tiny" "Tory" "Tily"))
T y 
NIL

我承认这不是算法......只是一种使用现有功能在lisp中执行此操作的方法

如果你想手动完成,如上所述,你循环比较给定索引的所有字符。如果它们都匹配,则保存匹配的字符。