Shortest substring containing three short strings

这是一个关于LeetCode的问题,要求在长字符串s中找到包含三个不同长度的短字符串a、b和c的最短子串。示例情况是,给定s和特定的a、b、c,返回包含这三个字符串的最短子串。

@(leetcode)[字符串, Google]

Problem

Given a long string s and short strings t1, t2, t3 (which can have different length) find the shortest substring of s which contains t1, t2 and t3.

Example:
s = "abcdefghijklmnopqrst", t1 = "abc", t2 = "cde", t3 = "klmn", return "abcdefghijklmn";

Solution

我们可以得到一个时间负责O(N),空间复杂度为O(1)的算法,因为题目中告知t1, t2, t3是short strings.具体的算法流程如下:
1.初始化,len为t的长度,len1-3分别为s1-3的长度,min_len=min(len1,len2,len3), max_len=max(len1, len2, len3),以及扫描的起始位置idx,s1-3找到匹配时候的索引idx1-3 
2.从idx开始,查看是否找到s1的匹配,如果找到更新idx1的位置,并且判断idx1,idx2,idx3是否都大于0,如果是,则可以根据这三个位置以及他们各自的长度求出当前包含它们的最小子字符串。并更新结果。
3.同理,依次检查s2, s3是否找到匹配,如果找到就进行与步骤2一样的处理。
4.做一点小的优化,如果在某次循环中得出的子字符串长度已经等于max_len,那么就没有比较继续搜索,此时的子字符串就是结果。

Code

#include <iostream>
#include <string>
#include <utility>
#include <cstring>
#include <algorithm>
#include <cassert>

using namespace std;

typedef pair<int, int> sub_string;

int cal_end_idx(sub_string const &str) {
  return str.first + str.second;
}

//计算此时包含三个字符串的最小子字符串
void cal_shortest_sub_str(int idx1, int idx2, int idx3, size_t len1,
                          size_t len2, size_t len3, sub_string& res) {
  if(idx1 < 0 || idx2 < 0 || idx3 < 0) {
    return;
  }
  size_t start_idx = min(min(idx1, idx2), idx3);
  size_t end_idx = max(max(idx1 + len1, idx2 + len2), idx3 + len3);
  int tmp_sub_len = (end_idx - start_idx);
  if(tmp_sub_len < res.second) {
    res.first = start_idx;
    res.second = tmp_sub_len;
  }
}

string find_shortest_sub_string(const string &s, const string &s1, const string &s2, const string &s3) {
  if(s.empty() || s1.empty() || s2.empty() || s3.empty()) {
    return "";
  }
  size_t len = s.size(), len1 = s1.size(), len2 = s2.size(), len3 = s3.size();
  size_t max_len = max(max(len1, len2), len3);
  size_t min_len = min(min(len1, len2), len3);
  const char* s_str = s.c_str(), *s1_str = s1.c_str(), *s2_str = s2.c_str(), *s3_str = s3.c_str();
  int idx1 = -1, idx2 = -1, idx3 = -1;
  sub_string result = make_pair(0, len);
  for(int idx = 0; (idx + min_len) < len; ++idx) {
    if(0 == strncmp(s_str + idx, s1_str, len1)) {
      idx1 = idx;
      cal_shortest_sub_str(idx1, idx2, idx3, len1, len2, len3, result);
    }
    if(0 == strncmp(s_str + idx, s2_str, len2)) {
      idx2 = idx;
      cal_shortest_sub_str(idx1, idx2, idx3, len1, len2, len3, result);
    }
    if(0 == strncmp(s_str + idx, s3_str, len3)) {
      idx3 = idx;
      cal_shortest_sub_str(idx1, idx2, idx3, len1, len2, len3, result);
    }
    //如果此时子字符串的长度已经是max_len,已经找到结果,直接跳出循环
    if(result.second == max_len) {
      break;
    }
  }
  if(idx1 < 0 || idx2 < 0 || idx3 < 0) {
    return "";
  }
  return s.substr(result.first, result.second);
}

void Test()
{
    {
        const std::string input("abc0123456789aksdfjasd");
        const std::string s1("0123");
        const std::string s2("3456");
        const std::string s3("");
        std::string result = find_shortest_sub_string(input, s1, s2, s3);
        cout << "cal : " << result << " answer : " <<  "empty" << endl;
        assert(result.empty() == true);
    }

    {
        const std::string input("abc0123456789aksdfjasd");
        const std::string s1("0123456");
        const std::string s2("3456");
        const std::string s3("1234");
        std::string result = find_shortest_sub_string(input, s1, s2, s3);
        cout << "cal : " << result << " answer : " << "0123456" << endl;
        assert(result == std::string("0123456"));
    }

    {
        const std::string input("abc0123456789aksdfjasd");
        const std::string s1("0123");
        const std::string s2("3456");
        const std::string s3("6789");
        std::string result = find_shortest_sub_string(input, s1, s2, s3);
        cout << "cal : " << result << " answer : " << "0123456789" << endl;
        assert(result == std::string("0123456789"));
    }

    {
        const std::string input("sdfa01234ad23456dfad6789abc0123456789aksdfjasd");
        const std::string s1("0123");
        const std::string s2("3456");
        const std::string s3("6789");
        std::string result = find_shortest_sub_string(input, s1, s2, s3);
        cout << "cal : " << result << " answer : " << "0123456789" << endl;
        assert(result == std::string("0123456789"));
    }

    {
        const std::string input(
               "sdfa01234ad23456dfad6789abc0123456789aksdfjasd0123skd3456kjsd6789jhs");
        const std::string s1("0123");
        const std::string s2("3456");
        const std::string s3("6789");
        std::string result = find_shortest_sub_string(input, s1, s2, s3);
        cout << "cal : " << result << " answer : " << "0123456789" << endl;
        assert(result == std::string("0123456789"));
    }
}

int main() {
  Test();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值