如何检查一个字符串是否包含另一个字符串,并且其中的字符顺序相同?

6

我刚开始学习,对如何做这个完全没有头绪。

我想要检查一个字符串是否包含另一个更小的字符串,并且如果这个字符串按顺序包含了另一个字符串中的字母,则返回true。

我不确定如何确保第二个字符串的字母按顺序排列,即使它们之间有其他字母。

例如,“chemistry”将针对字符串“hit”返回true。

但是对于字符串“him”,将返回false。

非常感谢任何帮助。

编辑:谢谢,我把“子字符串”这个词改成了“字符串”。正如我所说,我刚开始学习,还不知道它意味着别的什么。我真的很感激所有的帮助。这将让我朝着正确的方向前进。


3
你可能注意到一些回答和评论误解了你的问题。原因是,“子字符串”这个术语实际上有一个非常标准的意义,而这个非常标准的意义与你的意思不同。(当然,如果他们仔细阅读你的问题,他们会意识到你的意图并不是他们所想象的那样)。 - ruakh
谢谢,我已经修改了。对此我向大家道歉。 - Rocket
7
没有任何努力的展示,却得到了七个赞?! - lockstock
@lockstock 这是一个有趣的问题集。 - Ryan
6个回答

6

一般的方法是遍历较长的字符串("chemistry"),始终跟踪从较短字符串("hit")中需要的下一个字符的索引(首先为0,然后是1当你找到h时,接着是2当你找到i时,最后当你找到t时就完成了)。例如:

public static boolean containsSubsequence(
        final String sequence, final String subsequence) {
    if (subsequence.isEmpty()) {
        return true;
    }
    int subsequenceIndex = 0;
    for (int i = 0; i < sequence.length(); ++i) {
        if (sequence.charAt(i) == subsequence.charAt(subsequenceIndex)) {
            ++subsequenceIndex;
            if (subsequenceIndex == subsequence.length()) {
                return true;
            }
        }
    }
    return false;
}

3

因为您没有发布任何代码,所以我将解释我的做法。

  • 逐个字母迭代所有子字符串,在您的示例 "hit" 上操作
  • 检查当前字母(迭代 0 是 h)是否在此字符串中,如果/当找到,删除它之前出现的所有字符并从那里开始新的字符串(emistry)
  • 对所有左侧子字符串执行此过程
  • 使用控制布尔变量查看其是否已找到。
  • 如果在任何迭代中没有找到,则返回 false。

2
好的,您可以同时遍历两个字符串,只有在子序列(正确术语为“子序列” - “mist”是“chemistry”的子字符串,但“hit”仅是一个子序列)中的当前字符与外部字符串中的当前字符匹配时,才将索引推进到“子字符串”。也就是说,在“chemistry”和“hit”中,您从索引 i = 0,j = 0 开始。您将索引 i 递增到第一个字符串中,直到遇到s1.charAt(i) == s2.charAt(j),这种情况对于 i = 1 (化学中的第二个字符是h)成立。然后你增加,现在又再次增加,直到你碰到一个“i”(i=4)。如果最后满足j==s2.length(),则第二个字符串包含在第一个字符串中作为一个子序列。请注意,在这里 - 与更复杂的问题(例如测试第二个字符串是否真的是一个“子字符串”)不同,贪心策略有效,这意味着您不必担心与第二个字符串中的当前字符匹配的多个出现之一;您总是可以“贪婪地”选择您看到的第一个。
或者,您可以使用正则表达式:将第二个(搜索)字符串转换为正则表达式模式String pat =“.*h.*i.*t.*”,并测试s1.matches(pat)

1
你可以尝试以下方法(不确定效率如何):
  1. 将搜索字符串 "hit" 视为字符数组:["h","i","t"]
  2. 使用 indexOf(c) 确定是否能找到数组中的第一个字符。
  3. 在剩余的子字符串上重复此搜索。
下面是代码:
public class SearchString {
    public static void main(String[] args) {
        String searchSpace = "this is where to search?";
        String needle = "tweus?";
        char[] chars = needle.toCharArray();
        int index = 0;
        boolean found = true;
        int startIndex = 0;
        while (found && index < chars.length){
            searchSpace = searchSpace.substring(startIndex);
            startIndex = searchSpace.indexOf(chars[index]);
            found = (startIndex != -1);
            index++;
        }
        if (index==chars.length && found){
            System.out.println("Found it");
        } else {
            System.out.println("Nothing here");
        }
    }
}

1

基于@ruakh的解决方案稍作修改后得到以下答案:

public static boolean containsSubsequence(final String sequence, final String subsequence) {
    if (Objects.requireNonNull(sequence).isEmpty() || Objects.requireNonNull(subsequence).isEmpty() || subsequence.length() > sequence.length()) {
        return false;
    }
    int index = 0;
    for (int i = 0; i < sequence.length(); i++) {
        if (sequence.charAt(i) == subsequence.charAt(index) && ++index == subsequence.length()) {
            return true;
        }
    }
    return false;
}

Objects.requireNonNull() 是从Java 7开始的,如果你不在Java 7上,请记得替换成类似的东西(来自Apache Commons's StringUtils?)。验证假定返回false适用于空序列或子序列,否则您可能需要考虑抛出类似IllegalArgumentException的内容。

为了紧凑,两个if语句已经合并成一个单独的子句。

编辑: 如果您对数学倾向,或者遵循@ruakh的原始解决方案,则任何序列都应包含一个空子序列。我上面的代码之所以这样做是因为我喜欢将空参数想象为一种无效参数,因此返回false。它真的取决于该方法的使用方式以及空参数的“严重程度”。


0

我知道这个问题是关于Java的。但是只是为了参考,这里有一个C语言版本的。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int find_str_in_str(const char* const base, const char* const sub)
{
        int base_len = strlen(base);
        int sub_len  = strlen(sub);    
        char *tmp_sub = NULL;

        /* allocate enough mem for the max string length */
        if(base_len > sub_len) {
                tmp_sub = malloc(base_len + 1);
        } else {
                tmp_sub = malloc(sub_len + 1);
        }

        if(NULL == tmp_sub) {
                fprintf(stderr, "Runtime error (malloc)\n");
                exit(1);
        }

        int i = 0;
        int j = 0;

        for(; i < sub_len; i++) {
                for(; j < base_len; j++) {
                        if(base[j] == sub[i]) {
                                tmp_sub[i] = base[j];
                                /* the first occurance was found */
                                break;
                        }
                }
        }

        tmp_sub[i++] = '\0';

        if(0 == strcmp(sub, tmp_sub)) {
                free(tmp_sub);
                return 1;
        } else {
                free(tmp_sub);
                return 0;
        }
}





int main(int argc, char **argv)
{
        if(argc < 3) {
                fprintf(stderr, "Usage: %s %s %s\n", argv[0], "base", "derived");
                return EXIT_FAILURE;
        }

        if(1 == find_str_in_str(argv[1], argv[2])) {
                printf("true\n");
        } else {
                printf("false\n");
        }
        return EXIT_SUCCESS;
}

编译命令:gcc -Wall -Wextra main.c -o main

主函数自身 ELF

主函数化学尝试

主函数化学打击

主函数化学计时


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接