前两天同事遇到了一个小需求,想判断一个集合是不是在另一个集合中存在,并且要求顺序一致,然后一起讨论了下应该怎么做,有没有什么比较好的方式?下面分享一下我们想到的方法,如果你也有不同的想法也可以分享给我。

01解法一:序列化字符串(不推荐)

这个方案的核心思想就是如果一个集合是另一个集合的连续子序列,那么这两个集合序列化成字符串应该也还会有这样的特性,即一个字符串包含了另一个字符串。我立马想到了用string.Join把数组拼接成字符串,具体代码实现如下:

public static bool IsSubsequenceJoin(IEnumerable<string> main, IEnumerable<string> sub)
{
var mainString = string.Join(",", main);
var subString = string.Join(",", sub);
return mainString.Contains(subString);
}

其实听到序列化我第一反应是感觉有坑的,因为序列化会涉及到一些特殊字符的问题,还记得我之前的文章《“hello”.IndexOf(“\0”,2)中的坑》吗,就是因为特殊字符串引起。

当然上面的方法应对大多数需求应该没问题,但是还是有些特例需要注意,比如下面这个例子:

string[] main = ["a", "b", "c", "d,e"];
string[] sub = ["d", "e"];
var isSubsequenceJoin = ContinuousSubsequence.IsSubsequenceJoin(main, sub);
Console.WriteLine("数组 [\"a\", \"b\", \"c\", \"d,e\"] 序列化后: " + string.Join(",", main));
Console.WriteLine("数组 [\"d\", \"e\"] 序列化后: " + string.Join(",", sub));
Console.WriteLine("mainString.Contains(subString) 结果: " + isSubsequenceJoin);

运行结果如下:

因为string.Join使用了“,“作为拼接,所以sub数组序列化后就是"d,e",而数组main中恰好有个元素"d,e",这就导致预期之外的错误结果。

既然string.Join方法有缺陷还有其他序列化方法吗?我们试试专门做序列化的方法JsonConvert.SerializeObject,代码如下:

public static bool IsSubsequenceSerialize(IEnumerable<string> main, IEnumerable<string> sub)
{
var mainString = JsonConvert.SerializeObject(main).TrimStart('[').TrimEnd(']');
var subString = JsonConvert.SerializeObject(sub).TrimStart('[').TrimEnd(']');
return mainString.Contains(subString);
}

这个方法需要我们处理一些序列化产生的额外结构数据,比如上面的TrimStart('[').TrimEnd(']'),就是为了去掉数组产生的额外字符,如果要是其他更复杂类型可以要考虑的情况更多。

当然这个方法就可以解决上面的特例问题,但是依然有些特殊情况会导致错误,比如下面的示例:

string[] main = ["a", "b", "c", "d,\"e"];
string[] sub = ["e"];
var isSubsequenceSerialize = ContinuousSubsequence.IsSubsequenceSerialize(main, sub);
Console.WriteLine("IsSubsequenceSerialize 方法: ");
Console.WriteLine("数组 main [\"a\", \"b\", \"c\", \"d,\\\"e\"] 序列化后: " + JsonConvert.SerializeObject(main).TrimStart('[').TrimEnd(']'));
Console.WriteLine("数组 sub [\"e\"] 序列化后: " + JsonConvert.SerializeObject(sub).TrimStart('[').TrimEnd(']'));
Console.WriteLine("mainString.Contains(subString) 结果: " + isSubsequenceSerialize);

结果如下:

这个例子因为我们在构建数组main时,在一个元素中多加了一个符合[ “ ],使得结果出现预期之外的错误结果。

因此对于序列化字符串方式在大多数情况下都是不推荐使用的,除非你能保证你的数据不会出现一些特殊情况,如果数量大可能还会有性能问题。

02解法二:滑动窗口(推荐)

我们简单解释一下滑动窗口算法是啥意思,先看一下下面这张图感受一下。

滑动窗口可以理解成在一个长轴上,滑动一个窗口,因为窗口大小是固定的,所以随着时间推移,从窗口中看到的东西是不一样的。

把我们的问题和上图结合起来看,如果主数组main代表长轴,子数组sub代表窗口,现在我们把子数组窗口对齐主数组起始位置,然后时间轴每前进一个刻度代表子数组沿着主数组向前移动一位数。

当时间刻度来到T2时,从子数组窗口中可以看到数组[1,3,5],当时间刻度来到T8时,从子数组窗口中可以看到数组[8,7,6]。

也就是说随着时间的推进,当子数组窗口中看到的数组和自身数组值一样时,则代表子数组是主数组的连续子序列。具体实现代码如下:

public static bool IsSubsequenceSlidingWindow<T>(IEnumerable<T> main, IEnumerable<T> sub)
{
var mainLength = main.Count();
var subLength = sub.Count();
for (int i = 0; i < mainLength - subLength + 1; i++)
{
var expect = main.Skip(i).Take(subLength);
if (expect.SequenceEqual(sub))
{
return true;
}
}
return false;
}

注: 相关源码都已经上传至代码库,有兴趣的可以看看。

https://gitee.com/hugogoos/Planner

C#|.net core 基础 - 如何判断连续子序列的更多相关文章

  1. POJ-最大连续子序列和

    给定一个整数序列,找到一个具有最大和的连续子序列(子序列最少包含一个元素),返回其最大和. 实例输入: -2, 1, -3, 4, -1, 2, 1, -5, 4 实例输出: 6(连续子序列4, -1 ...

  2. 【基础练习】【线性DP】codevs2622 数字序列(最大连续子序列和)题解

    版权信息 转载请注明出处 [ametake版权全部]http://blog.csdn.net/ametake欢迎来看 这道题目本质就是朴素的最大连续子序列和 直接上题目和代码 题目描写叙述 Descr ...

  3. 最大连续子序列乘积(DP)

    题目来源:小米手机2013年校园招聘笔试题 题目描述: 给定一个浮点数序列(可能有正数.0和负数),求出一个最大的连续子序列乘积. 输入: 输入可能包含多个测试样例.每个测试样例的第一行仅包含正整数 ...

  4. hdoj 1231 最大连续子序列

    最大连续子序列 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Sub ...

  5. dp经典问题-最大连续子序列和 hdu1003

    题目描述: 这道题我先后做过三遍,结果每一遍都没有做出来.今天再仔仔细细的研究了一下,才发现用动态规划更好理解. 关于求最大连续子序列和的博文转载如下:https://www.cnblogs.com/ ...

  6. hdu1003 Max Sum【最大连续子序列之和】

    题目链接:https://vjudge.net/problem/HDU-1003 题目大意:给出一段序列,求出最大连续子序列之和,以及给出这段子序列的起点和终点. 解题思路:最长连续子序列之和问题其实 ...

  7. HDU——最大连续子序列(区间DP)

    上一个题的加强版! 最大连续子序列 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  8. 题解报告:hdu1231最大连续子序列

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1231 Problem Description 给定K个整数的序列{ N1, N2, ..., NK } ...

  9. ASP.NET Core 登录登出 - ASP.NET Core 基础教程 - 简单教程,简单编程

    原文:ASP.NET Core 登录登出 - ASP.NET Core 基础教程 - 简单教程,简单编程 ASP.NET Core 登录登出 上一章节我们总算完善了注册的功能,而且也添加了一个用户,现 ...

  10. HDU 1231 最大连续子序列 (动态规划)

    最大连续子序列 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Sub ...

随机推荐

  1. Web 安全:OWASP TOP10 漏洞介绍

    OWASP TOP 10漏洞是指由Open Web Application Security Project(OWASP)发布的十大最严重. 最普遍的Web应用程序安全漏洞.这些漏洞在当今的Web应用 ...

  2. CentOS之yum安装JDK

    1.查看云端目前支持安装的jdk版本 [root@localhost ~]# yum search java|grep jdk ldapjdk-javadoc.noarch : Javadoc for ...

  3. Pandas库学习笔记(5)---Pandas Panel

    Pandas Panel Pandas Panel基本操作 Panel数据3D容器. 术语 Panel data 源自计量经济学,名称来之于pandas − pan(el)-da(ta)-s. 3个轴 ...

  4. 踩坑记录:windows11下使用 VS2022 和 PCL1.14.1 配置点云开发环境

    闲话不多说,具体在windows下下载PCL与解压pcl可以看https://www.yuque.com/huangzhongqing/pcl/这位大佬的文章,那我就具体说一下踩过点坑: 踩坑点1: ...

  5. ipa文件上传到app store的构建版本的工具

    打包好ipa文件后,可以使用mac电脑上的xcode将ipa上传到app store的构建版本中,假如没有mac电脑,可以使用香蕉云编来将ipa文件上传到构建版本. 这里我们来介绍下ipa文件上传到a ...

  6. 【Java】实体类转换框架 MapStruct

    简单尝试了下发现比Dozer还有BeanUtil还方便小巧 注解的作用是在生成字节码文件时实现具体GetterSetter方法,实际转换时就是赋值操作,嘎嘎快 参考文章: https://juejin ...

  7. 【SpringMVC】03 使用注解

    第一步还是配置web.xml,使用分发器统一处理请求和加载容器文件 <?xml version="1.0" encoding="UTF-8"?> & ...

  8. 【Linux】真机安装CentOS8

    先制作启动U盘 https://www.cnblogs.com/mindzone/p/12961506.html 插入电脑,开机[这里我是把电脑硬盘格式化了,不会在电脑磁盘上找到任何系统,直接跳到启动 ...

  9. 【Vue】Re11 Vue 与 Webpack

    一.案例环境前置准备: 创建一个空目录用于案例演示 mkdir vue-sample 初始化案例和安装webpack cd vue-sample npm install webpack@3.6.0 - ...

  10. 使用 addRouteMiddleware 动态添加中间

    title: 使用 addRouteMiddleware 动态添加中间 date: 2024/8/4 updated: 2024/8/4 author: cmdragon excerpt: 摘要:文章 ...