我正在尝试编写一个代码,告诉我一个字符串是否是另一个字符串的子字符串。问题在于,如果中间有字符并且唯一重要的字符是'A'
,'T'
,'G'
和'C'
,则无关紧要。例如:
"TxxAA" is a subsequence of "CTyyGCACA"
"pln" is a subsequence of "oiu"
"TAA" is NOT a subsequence of "TCCCA"
目前我在做
private boolean subSequence(DNASequence other) {
other.fix();
boolean valid = false;
String t = other.toString();
data = dataFix(data);
int index = 0;
for (int i = 0; i < data.length(); i++) {
for (int j = 0; j < t.length(); j++) {
if(data.charAt(i) == t.charAt(j)) {
if( j >= index) {
valid = true;
index = j;
t = t.replace(t.charAt(j), '_');
} else {
valid = false;
}
}
}
}
if (data == "" || t == "" ) {
valid = true;
}
return valid;
}
private String dataFix(String data) {
for (int i = 0; i < data.length(); i += 1) {
char ch = data.charAt(i);
if (("ATGC".indexOf(ch) < 0))
data = data.replace(data.charAt(i), ' ');
}
data = data.replaceAll(" ", "").trim();
return data;
}
fix()
和dataFix()
方法会删除"ATGC"
以外的所有字符。随着代码的迭代,它将t
中与data.charAt(i)
匹配的字符替换为_
,以便它不会重新匹配相同的字母(我遇到了这个问题)。
目前,正在发生的事情是,replace函数正在替换字符串中的每个字符,而不仅仅是特定索引处的char(这是它应该做的)。有什么更好的方法来解决这个问题?我哪里错了?谢谢。
答案 0 :(得分:4)
要回答第一个问题&#39;什么是解决此问题的更好方法?&#39;,我建议使用正则表达式(或正则表达式)。正则表达式是一种表达文本模式的方式。
对于您有搜索字词的示例:
T.*A.*A
用于描述您正在寻找的模式的正则表达式可以是:
public class DnaMatcher {
static boolean isSearchChar(char c) {
return 'A' == c || 'T' == c || 'G' == c || 'C' == c;
}
static Pattern preparePattern(String searchSequence) {
StringBuilder pattern = new StringBuilder();
boolean first = false;
for (char c : searchSequence.toCharArray()) {
if (isSearchChar(c)) {
if (first) {
first = false;
} else {
pattern.append(".*");
}
pattern.append(c);
}
}
return Pattern.compile(pattern.toString());
}
static boolean contains(String sequence, String searchSequence) {
Pattern pattern = preparePattern(searchSequence);
Matcher matcher = pattern.matcher(sequence);
return matcher.find();
}
public static void main(String...none) throws Exception {
System.out.println(contains("CTyyGCACA", "TxxAA")); // true
System.out.println(contains("TCCCA", "TAA")); // false
}
}
没有详细说明术语。*是任何数字(零个或多个)任何字符的表达式。所以这个正则表达式描述了一个模式:T;那么任何人物;一个;那么任何人物;然后是A。
您的原始问题变为&#34;序列是否具有模式为T. * A. * A?&#34;的子序列。 Java内置了一个正则表达式库,您可以使用Pattern和Matcher对象来回答这个问题。
一些示例代码作为演示:
add_filter( 'job_manager_indeed_get_jobs_args', 'custom_job_manager_indeed_get_jobs_args' );
function custom_job_manager_indeed_get_jobs_args( $args ) {
$args['q'] = $search_keywords ? $search_keywords . "designer" : "designer";
return $args;
}
您可以看到preparePattern匹配准备正如所讨论的正则表达式。
答案 1 :(得分:4)
了解字符串可能很长,正则表达式检查可能需要一些时间。
static String fix(String s) {
return s.replaceAll("[^ACGT]+", "");
}
static boolean isSubSequence(String sought, String chain) {
sought = fix(sought);
chain = fix(chain);
char[] soughtChars = sought.toCharArray();
char[] chainChars = chain.toCharArray();
int si = 0;
for (int ci = 0; si < soughtChars.length && ci < chainChars.length; ++ci) {
if (chainChars[ci] == soughtChars[si]) {
++si;
}
}
return si >= soughtChars.length;
}
或者
static boolean isSubSequence(String sought, String chain) {
sought = fix(sought);
chain = fix(chain);
int ci = 0;
for (char ch : sought.toCharArray()) {
ci = chain.indexOf(ch, ci);
if (ci < 0) {
return false;
}
++ci;
}
return true;
}
问题似乎更像这种结果。
与正则表达式比较:
我做了一个比较:
StringBuilder sb = new StringBuilder(10_000);
Random random = new Random(42);
for (int i = 0; i < 10_1000 - 6; ++i) {
sb.append("ACGT".charAt(random.nextInt(3)));
}
sb.append("TTAGTA");
String s = sb.toString();
String t = "TAGAAG";
{
long t0 = System.nanoTime();
boolean found = contains(s, t);
long t1 = System.nanoTime();
System.out.printf("Found: %s in %d ms%n", found, (t1 - t0) / 1000_000L);
}
{
long t0 = System.nanoTime();
boolean found = isSubSequence(t, s);
long t1 = System.nanoTime();
System.out.printf("Found: %s in %d ms%n", found, (t1 - t0) / 1000_000L);
}
结果
Found: false in 31829 ms --> Regex
Found: false in 5 ms --> indexOf
但是:这个案子非常人为:短串上失败。
答案 2 :(得分:1)
可以使用(相对)简单的递归来完成:
/**
* Returns true is s1 is a subsequence of s2, false otherwise
*/
private static boolean isSubSeq(String s1, String s2) {
if ("".equals(s1)) {
return true;
}
String first = s1.substring(0, 1);
s1 = s1.substring(1);
int index = s2.indexOf(first);
if (index == -1) {
return false;
}
s2 = s2.substring(index+1);
return isSubSeq(s1, s2);
}
算法:在s2中查找s1的第一个字符的第一个索引,如果没有这样的索引 - 答案是假的,如果有,我们可以继续寻找(递归)从位置索引+ 1开始的下一个字母
修改强>
您似乎需要清理输入以仅包含字符:'A','T','G','C'
这很容易做到(在Java 9上运行之后,但很容易修改为Java的低版本):
private static String sanitize(String s) {
String result = "";
List<Character> valid = List.of( 'A', 'T', 'G', 'C');
for (char c : s.toCharArray()) {
if (valid.contains(c)) {
result += c;
}
}
return result;
}
然后使用如下(示例):
public static void main(String[] args) {
String s1 = "TxxAA";
String s2 = "CTyyGCACA";
s1 = sanitize(s1); // you need to sanitize only s1, can you see why?
System.out.println(isSubSeq(s1, s2));
}