精选算法题(4)——字符串比较

简介: 精选算法题(4)——字符串比较

题目描述:

好久没做题目了,近期刷抖音碰到一个题目,乍一看不是很难,但是手生了,就写个玩玩,大家轻喷。


两个字符串比较,如abcdefg和25abdfxx,返回:位置0多出:25;位置2缺少:c;位置4缺少:e;位置6错误,应为g。


解题思路:

我看很多人说双指针法、动态规划能解,我暂时没想那么多,就用了简单的双循环+滑动窗口。


  1. 取idx1和idx2作为滑动窗口起点。以字符串1为基准,遍历字符串2寻找相同的字符。
  2. 当两个字符一致时,判断下j和idx2的大小情况,如果j大且i和idx1一致,说明字符串2相同字符前面有一段字符是多出的。之后,将idx1加1,再使idx2等于j+1,这样可以使两个字符串的滑动窗口从相同字符后的一个位置开始。
  3. 如果i大于idx1,且j和idx2一致,同理,说明字符串1相同字符前面缺少了一段字符。之后,idx2加1,idx1等于i+1即可。
  4. 如果i大于idx1,j也大于idx2,说明两个字符串相同字符前,各有一段不相同字符,即匹配错误。
  5. 若上述三个条件都不满足,那就说明碰到了连续相同字符串。令idx1和idx2都加1,跳过即可。
  6. 如果i走到最后都没找到匹配对象,则从idx1到字符串1结尾所有字符都匹配失败了。

测试代码:

#include <iostream>
#include <string>
using namespace std;
void compareStrings(std::string str1, std::string str2) {
  int len1 = str1.length();
  int len2 = str2.length();
  int idx1 = 0;
  int idx2 = 0;
  for (int i = 0; i < len1; ++i) {
    for (int j = idx2; j < len2; ++j) {
      if (str1[i] == str2[j]) {
        if (j > idx2 && i == idx1) {
          cout << "位置" << i << "多出:" << str2.substr(idx2, j - idx2) << endl;
          idx1++;
          idx2 = j + 1;
        }
        else if (i > idx1 && j == idx2) {
          cout << "位置" << idx1 << "缺少:" << str1.substr(idx1, i - idx1) << endl;
          idx1 = i + 1;
          idx2++;
        }
        else if (i > idx1 && j > idx2) {
          cout << "位置" << idx1 << "错误,应为:" << str1.substr(idx1, i - idx1) << endl;
          idx1 = i + 1;
          idx2= j + 1;
        }
        else{
          idx1++;
          idx2++;
        }
        break;
      }     
    }
    if (i == (len1 - 1) && (idx1 < len1)) {
      cout << "位置" << idx1 << "错误,应为:" << str1.substr(idx1, i - idx1 + 1) << endl;
    }
  }
}
int main() {
  std::string str1 = "abcdefg";
  std::string str2 = "25abdfxx";
  cout << "字符串1:" << str1 << endl;
  cout << "字符串2:" << str2 << endl;
  compareStrings(str1, str2);
  return 0;
}

测试结果:

字符串如题目要求时,结果如下,可以发现是满足的。

加几个字符再试试,依然可行。

中间内容再打乱一些,暂无问题。

多几个重复字符,按照我的逻辑,输出结果是对的,但不知道题目是不是这意思。

      如果代码有什么需要改进的或者有什么bug,欢迎评论留言,我会及时更正以免误导他人~

      如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!


      有朋友提出了问题,所以我对算法进行了改进。

  1. 基于动态规划表获取两个字符串的最长非连续重复子串。
  2. 用子串作为参照物,逐一字符遍历。取两个字符串在该字符前的字符串比较,根据不同情况做出不同反馈,具体参见代码和注释。

测试代码:

#include <iostream>
#include <string>
#include <vector>
#include <math.h>
#include <algorithm>
using namespace std;
// 获取最长重复子串(可不连续)
string getSubString(std::string str1, std::string str2) {
  int len1 = int(str1.length());
  int len2 = int(str2.length());
  // 动态规划
  vector<vector<int>> m(len1 + 1, vector<int>(len2 + 1, 0));
  vector<vector<string>> s(len1 + 1, vector<string>(len2 + 1, ""));
  for (int i = 1; i <= len1; ++i){
    for (int j = 1; j <= len2; ++j){
      if (str1[i - 1] == str2[j - 1]){
        m[i][j] = m[i - 1][j - 1] + 1;
        s[i][j] = s[i - 1][j - 1] + str1[i - 1];
      }
      else{
        if (m[i - 1][j] > m[i][j - 1]){
          m[i][j] = m[i - 1][j];
          s[i][j] = s[i - 1][j];
        }
        else{
          m[i][j] = m[i][j - 1];
          s[i][j] = s[i][j - 1];
        }
      }
    }
  }
  return s[len1][len2];
}
// 比较字符串
void compareString(string str1, string str2, string substr) {
  int len1 = int(str1.length());
  int len2 = int(str2.length());
  int len3 = int(substr.length());
  // 以重复子串字符遍历
  // 若截止到第一个重复字符,t1空,t2有,那就是多出;t1有,t2空,那就是缺少。
  // 两个都空说明连续重复字符;若两个都不空,则说明错误。
  // 缺少和错误的状态按位置挨个字符输出。
  int idx1 = 0;
  int idx2 = 0;
  for (int i = 0; i < len3; ++i) {
    string t1, t2;
    int idx3 = idx1;
    int idx4 = idx2;
    // t1为字符串1在当前重复字符前的字符串
    for (int m = idx1; m < len1; ++m) {
      if (str1[m] == substr[i]) {
        t1 = str1.substr(idx1, m - idx1);
        idx1 = m + 1;
        break;
      }
    }
    // t2为字符串2在当前重复字符前的字符串
    for (int n = idx2; n < len2; ++n) {
      if (str2[n] == substr[i]) {
        t2 = str2.substr(idx2, n - idx2);
        idx2 = n + 1;
        break;
      }
    }
    // 根据不同情况处理
    if (t1 == "" && t2 != "") {
      cout << "位置" << idx3 << "多出:" << t2 << endl;
    }
    else if (t1 != "" && t2 == "") {
      while (t1 != "") {
        cout << "位置" << idx3 << "缺少:" << t1[0] << endl;
        idx3++;
        t1 = t1.substr(1, t1.size() - 1);
      }
    }
    else if (t1 == "" && t2 == "") {
    }
    else {
      while (t1 != "") {
        cout << "位置" << idx3 << "错误,应为:" << t1[0] << endl;
        idx3++;
        t1 = t1.substr(1, t1.size() - 1);
      }
    }
  }
  // 对尾巴数据处理
  if (idx1 < len1) {
    string tail = str1.substr(idx1, len1 - idx1);
    while (tail != "") {
      cout << "位置" << idx1 << "错误,应为:" << tail[0] << endl;
      idx1++;
      tail = tail.substr(1, 1);
    }
  }
}
int main() {
  std::string str1 = "1abcdefui";
  std::string str2 = "abxcegfui";
  cout << "字符串1:" << str1 << endl;
  cout << "字符串2:" << str2 << endl;
  // 获取最长重复子串(可不连续)
  string substr = getSubString(str1, str2);
  cout << "substring:" << substr << endl;
  // 比较字符串
  compareString(str1, str2, substr);
  system("pause");
  return 0;
}

测试代码:

相关文章
|
4月前
|
算法
【算法】滑动窗口——找到字符串中所有字母异位词
【算法】滑动窗口——找到字符串中所有字母异位词
|
2月前
|
算法
两个字符串匹配出最长公共子序列算法
本文介绍了最长公共子序列(LCS)问题的算法实现,通过动态规划方法求解两个字符串的最长公共子序列,并提供了具体的编程实现细节和示例。
97 1
两个字符串匹配出最长公共子序列算法
|
4月前
|
算法 Java
掌握算法学习之字符串经典用法
文章总结了字符串在算法领域的经典用法,特别是通过双指针法来实现字符串的反转操作,并提供了LeetCode上相关题目的Java代码实现,强调了掌握这些技巧对于提升算法思维的重要性。
|
5月前
|
自然语言处理 算法 搜索推荐
字符串相似度算法完全指南:编辑、令牌与序列三类算法的全面解析与深入分析
在自然语言处理领域,人们经常需要比较字符串,这些字符串可能是单词、句子、段落甚至是整个文档。如何快速判断两个单词或句子是否相似,或者相似度是好还是差。这类似于我们使用手机打错一个词,但手机会建议正确的词来修正它,那么这种如何判断字符串相似度呢?本文将详细介绍这个问题。
313 1
|
5月前
|
数据采集 算法 JavaScript
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
JavaScript字符串搜索涵盖`indexOf`、`includes`及KMP算法。`indexOf`返回子字符串位置,`includes`检查是否包含子字符串。KMP是高效的搜索算法,尤其适合长模式匹配。示例展示了如何在数据采集(如网页爬虫)中使用这些方法,结合代理IP进行安全搜索。代码示例中,搜索百度新闻结果并检测是否含有特定字符串。学习这些技术能提升编程效率和性能。
140 1
揭开JavaScript字符串搜索的秘密:indexOf、includes与KMP算法
|
4月前
|
算法 C++
惊爆!KPM算法背后的秘密武器:一行代码揭秘字符串最小周期的终极奥义,让你秒变编程界周期大师!
【8月更文挑战第4天】字符串最小周期问题旨在找出字符串中最短重复子串的长度。KPM(实为KMP,Knuth-Morris-Pratt)算法,虽主要用于字符串匹配,但其生成的前缀函数(next数组)也可用于求解最小周期。核心思想是构建LPS数组,记录模式串中每个位置的最长相等前后缀长度。对于长度为n的字符串S,其最小周期T可通过公式ans = n - LPS[n-1]求得。通过分析周期字符串的特性,可证明该方法的有效性。提供的C++示例代码展示了如何计算给定字符串的最小周期,体现了KPM算法在解决此类问题上的高效性。
92 0
|
6月前
|
存储 算法 Cloud Native
C++ bcrypt算法 字符串加密,亲测有效
C++ bcrypt算法 字符串加密,亲测有效
|
6月前
|
存储 算法
算法训练,牛客.判断是不是平衡二叉树 牛客.最大子矩阵两个数组的交集牛客.数组中两个字符串的最小距离
算法训练,牛客.判断是不是平衡二叉树 牛客.最大子矩阵两个数组的交集牛客.数组中两个字符串的最小距离
算法训练,牛客.判断是不是平衡二叉树 牛客.最大子矩阵两个数组的交集牛客.数组中两个字符串的最小距离
|
5月前
|
算法 Java
KMP算法详解及其在字符串匹配中的应用
KMP算法详解及其在字符串匹配中的应用
|
7月前
|
算法
KPM算法求字符串的最小周期证明
公式 `ans = n - LPS[n-1]` 描述了最小周期,其中 `n` 是子串长度,`LPS[n-1]` 是前缀函数值。证明分为特殊情况和一般情况:对于完整周期字符串,`LPS[n-1] = 3*T`,故 `ans = T`;对于非完整周期,通过分析不同长度的 `[末部分]` 和 `[前部分]`,展示 `ans` 始终等于周期 `T` 或由 `[e][b]` 构成的最小周期,从而证明公式正确。