字符串相关

文章目录

  • 字符串基础
      • 字符串的存储
  • 标准库
  • 字符串匹配
        • 单串匹配
        • 多串匹配
        • 其他类型的字符串匹配问题
  • 字符串哈希
      • Hash 的实现
      • Hash 的分析与改进
        • 错误率
        • 多次询问子串哈希
      • Hash 的应用
        • 字符串匹配
        • 允许 k次失配的字符串匹配
        • 最长回文子串
        • 最长公共子字符串
        • 确定字符串中不同子字符串的数量
  • 字典树 (Trie)
      • 应用
        • 检索字符串
        • AC 自动机
        • 维护异或极值
  • AC 自动机
  • Manacher

字符串基础

在这里插入图片描述

字符串的存储

  1. 使用 char 数组存储,用空字符 \0 表示字符串的结尾。(C 风格字符串)
  2. 使用 C++ 标准库提供的 string 类。
  3. 字符串常量可以用字符串字面值(用双引号括起来的字符串)表示。

标准库

C 标准库是在对字符数组进行操作:char[]/const char*

代码作用
strlen(const char *str)返回从 str[0] 开始直到 ‘\0’ 的字符数。注意,未开启 O2 优化时,该操作写在环条件中复杂度是 O(n)O(n)O(n)的。
printf("%s", s)用 %s 来输出一个字符串(字符数组)。
scanf("%s", &s)用 %s 来读入一个字符串(字符数组)。
sscanf(const char *__source, const char *__format, …)从字符串 __source 里读取变量,比如 sscanf(str,"%d",&a)。
sprintf(char *__stream, const char *__format, …)将 __format 字符串里的内容输出到 __stream 中,比如 sprintf(str,"%d",i)。
strcmp(const char *str1, const char *str2)按照字典序比较 str1 str2 若 str1 字典序小返回负值,两者一样返回 0,str1 字典序更大则返回正值。请注意,不要简单的认为返回值只有0 ,1,-1 三种,在不同平台下的返回值都遵循正负,但并非都是 0,-1,1。
strcpy(char *str, const char *src)把 src 中的字符复制到 str 中,str src 均为字符数组头指针,返回值为 str 包含空终止符号 ‘\0’。
strncpy(char *str, const char *src, int cnt)复制至多 cnt 个字符到 str 中,若 src 终止而数量未达 cnt 则写入空字符到 str 直至写入总共 cnt 个字符。
strcat(char *str1, const char *str2):将 str2 接到 str1 的结尾,用 *str2 替换 str1 末尾的 ‘\0’ 返回 str1。
strstr(char *str1, const char *str2)若 str2 是 str1 的子串,则返回 str2 在 str1 的首次出现的地址;如果 str2 不是 str1 的子串,则返回 NULL。
strchr(const char *str, int c)找到在字符串 str 中第一次出现字符 c 的位置,并返回这个位置的地址。如果未找到该字符则返回 NULL。
strrchr(const char *str, char c)找到在字符串 str 中最后一次出现字符 c 的位置,并返回这个位置的地址。如果未找到该字符则返回 NULL。

C++ 标准库是在对字符串对象进行操作,同时也提供对字符数组的兼容。 std::string

代码作用
重载了赋值运算符 +当 + 两边是 string/char/char[]/const char* 类型时,可以将这两个变量连接,返回连接后的字符串(string)。
赋值运算符 =右侧可以是 const string/string/const char*/char*。
访问运算符 [cur]返回 cur 位置的引用。
访问函数 data()/c_str()返回一个 const char* 指针,内容与该 string 相同。
容量函数 size()返回字符串字符个数。
find(ch, start = 0)查找并返回从 start 开始的字符 ch 的位置;rfind(ch) 从末尾开始,查找并返回第一个找到的字符 ch 的位置(皆从 0开始)(如果查找不到,返回 -1)。
substr(start, len)可以从字符串的 start(从 0开始)截取一个长度为 len 的字符串(缺省 len 时代码截取到字符串末尾)。
append(s)将 s 添加到字符串末尾。
append(s, pos, n)将字符串 s 中,从 pos 开始的 n 个字符连接到当前字符串结尾。
replace(pos, n, s)删除从 pos 开始的 n 个字符,然后在 pos 处插入串 s。
erase(pos, n)删除从 pos 开始的 n 个字符。
insert(pos, s)在 pos 位置插入字符串 s。
std::string重载了比较逻辑运算符,复杂度是 O(n)的。

字符串匹配

单串匹配

一个模式串 (pattern),一个待匹配串,找出前者在后者中的所有出现位置
举例:Oulipo HDU - 1686(哈希或KMP)匹配字符串

多串匹配

多个模式串,一个待匹配串(多个待匹配串可以直接连起来)。
直接当做单串匹配肯定是可以的,但是效率不够高。
举例:Keywords Search HDU - 2222(AC自动机模板)

其他类型的字符串匹配问题

例如匹配一个串的任意后缀、匹配多个串的任意后缀等。

字符串哈希

Hash 的核心思想在于,将输入映射到一个值域较小、可以方便比较的范围。

Warning
这里的“值域较小”在不同情况下意义不同。
在 哈希表 中,值域需要小到能够接受线性的空间与时间复杂度。
在字符串哈希中,值域需要小到能够快速比较(10910^9109101810^{18}1018 都是可以快速比较的)。
同时,为了降低哈希冲突率,值域也不能太小。

我们定义一个把字符串映射到整数的函数 fff,这个fff 称为是 Hash 函数。
我们希望这个函数 fff 可以方便地帮我们判断两个字符串是否相等。
具体来说,哈希函数最重要的性质可以概括为下面两条:

  1. 在 Hash 函数值不一样的时候,两个字符串一定不一样;
  2. 在 Hash 函数值一样的时候,两个字符串不一定一样(但有大概率一样,且我们当然希望它们总是一样的)。

Hash 函数值一样时原字符串却不一样的现象我们成为哈希碰撞。

我们需要关注的是什么?
时间复杂度和 Hash 的准确率。

通常我们采用的是多项式 Hash 的方法,对于一个长度为 lll 的字符串 s来说,我们可以这样定义多项式 Hash 函数:f(s)=∑i=1ls[i]×bl−i(modf(s)=\sum^{l}_{i=1}s[i]\times b^{l-i}(modf(s)=i=1ls[i]×bli(mod M)M)M)。例如,对于字符串xyzxyzxyz ,其哈希函数值为xb2+yb+zxb^2+yb+zxb2+yb+z
特别要说明的是,也有很多人使用的是另一种 Hash 函数的定义,即f(s)=∑i=1ls[i]×bi−1(modf(s)=\sum^{l}_{i=1}s[i]\times b^{i-1}(modf(s)=i=1ls[i]×bi1(mod M)M)M) ,这种定义下,同样的字符串 xyzxyzxyz的哈希值就变为了 x+by+zb2x+by+zb^2x+by+zb2 了。显然,上面这两种哈希函数的定义函数都是可行的,但二者在之后会讲到的计算子串哈希值时所用的计算式是不同的,因此千万注意 不要弄混了这两种不同的 Hash 方式。由于前者的 Hash 定义计算更简便、使用人数更多、且可以类比为一个 b 进制数来帮助理解,所以本文下面所将要讨论的都是使用 f(s)=∑i=1ls[i]×bl−i(modf(s)=\sum^{l}_{i=1}s[i]\times b^{l-i}(modf(s)=i=1ls[i]×bli(mod M)M)M) 来定义的 Hash 函数。

下面讲一下如何选择 M和计算哈希碰撞的概率。

这里 M 需要选择一个素数(至少要比最大的字符要大),b 可以任意选择。如果我们用未知数 x 替代b ,那么f(x)f(x)f(x) 实际上是多项式环ZM[x]\mathbb{Z}_{M}[x]ZM[x] 上的一个多项式。考虑两个不同的字符串 s,t有f(s)=f(t)f(s)=f(t)f(s)=f(t) 。我们记h(x)=f(s)−f(t)=∑i=1l(s[i]−t[i])xl−i(modh(x)=f(s)-f(t)=\sum^{l}_{i=1}(s[i]-t[i])x^{l-i}(modh(x)=f(s)f(t)=i=1l(s[i]t[i])xli(mod M)M)M) ,其中l=max(∣s∣,∣t∣)l=max(|s|,|t|)l=max(s,t) 。可以发现 h(x) 是一个 l−1l-1l1 阶的非零多项式。如果 s与t 在x=b 的情况下哈希碰撞,则 b是h(x) 的一个根。由于 h(x) 在ZM\mathbb{Z}_{M}ZM 是一个域(等价于 M 是一个素数,这也是为什么 M 要选择素数的原因)的时候,最多有l−1l-1l1 个根,如果我们保证 b 是从 [0,M) 之间均匀随机选取的,那么 f(s)f(s)f(s)f(t)f(t)f(t) 碰撞的概率可以估计为 l−1M\frac{l-1}{M}Ml1。简单验算一下,可以发现如果两个字符串长度都是 1 的时候,哈希碰撞的概率为 1−1M\frac{1-1}{M}M11=0,此时不可能发生碰撞。

Hash 的实现

参考代码:(效率低下的版本,实际使用时一般不会这么写)

using std::string;const int M = 1e9 + 7;
const int B = 233;typedef long long ll;int get_hash(const string& s) {int res = 0;for (int i = 0; i < s.size(); ++i) {res = (ll)(res * B + s[i]) % M;}return res;
}bool cmp(const string& s, const string& t) {return get_hash(s) == get_hash(t);
}

Hash 的分析与改进

错误率

若进行 n次比较,每次错误率 1M\frac{1}M{}M1,那么总错误率是1−(1−1M)n1-(1-\frac{1}{M})^{n}1(1M1)n。在随机数据下,若M=109+7M=10^{9}+7M=109+7n=106n=10^6n=106,错误率约为 11000\frac{1}{1000}10001,并不是能够完全忽略不计的。
所以,进行字符串哈希时,经常会对两个大质数分别取模,这样的话哈希函数的值域就能扩大到两者之积,错误率就非常小了。

多次询问子串哈希

单次计算一个字符串的哈希值复杂度是O(n) ,其中 n为串长,与暴力匹配没有区别,如果需要多次询问一个字符串的子串的哈希值,每次重新计算效率非常低下。
一般采取的方法是对整个字符串先预处理出每个前缀的哈希值,将哈希值看成一个b 进制的数对M 取模的结果,这样的话每次就能快速求出子串的哈希了:

fi(s)f_{i}(s)fi(s) 表示 f(s[1...i])f(s[1...i])f(s[1...i]),即原串长度为 iii 的前缀的哈希值,那么按照定义有 fi(s)=s[1]×bi−1+s[2]×bi−2+...+s[i−1]×b+s[i]f_i(s)=s[1]\times b^{i-1}+s[2]\times b^{i-2}+...+s[i-1]\times b+s[i]fi(s)=s[1]×bi1+s[2]×bi2+...+s[i1]×b+s[i]

现在,我们想要用类似前缀和的方式快速求出f(s[l...r])f(s[l...r])f(s[l...r]) ,按照定义有字符串 s[l...r]s[l...r]s[l...r]的哈希值为 f(s[l...r])=s[l]×br−l+s[l+1]×br−l−1+...+s[r−l]×b+s[r]f(s[l...r])=s[l]\times b^{r-l}+s[l+1]\times b^{r-l-1}+...+s[r-l]\times b+s[r]f(s[l...r])=s[l]×brl+s[l+1]×brl1+...+s[rl]×b+s[r]

对比观察上述两个式子,我们发现 f(s[l...r])=fr(s)−fl−1(s)×br−l+1f(s[l...r])=f_r(s)-f_{l-1}(s)\times b^{r-l+1}f(s[l...r])=fr(s)fl1(s)×brl+1 成立,因此我们用这个式子就可以快速得到子串的哈希值。其中br−l+1b^{r-l+1}brl+1 可以O(n) 的预处理出来然后O(1) 的回答每次询问(当然也可以快速幂 O(log n)的回答每次询问)。

Hash 的应用

字符串匹配

求出模式串的哈希值后,求出文本串每个长度为模式串长度的子串的哈希值,分别与模式串的哈希值比较即可。

允许 k次失配的字符串匹配

问题:给定长为 n 的源串 ,以及长度为m 的模式串 ,要求查找源串中有多少子串与模式串匹配。s′s's 与s 匹配,当且仅当 s′s's与s 长度相同,且最多有 k 个位置字符不同。其中 1≤n,m≤1061\leq n,m\leq 10^61n,m1060≤k≤50\leq k\leq 50k5

这道题无法使用 KMP 解决,但是可以通过哈希 + 二分来解决。

枚举所有可能匹配的子串,假设现在枚举的子串为s′s's ,通过哈希 + 二分可以快速找到 s′s's 与p 第一个不同的位置。之后将 s′s's 与 p 在这个失配位置及之前的部分删除掉,继续查找下一个失配位置。这样的过程最多发生 k 次。总的时间复杂度为O(m+knO(m+knO(m+kn log2log_2log2 m)m)m)

最长回文子串

二分答案,判断是否可行时枚举回文中心(对称轴),哈希判断两侧是否相等。需要分别预处理正着和倒着的哈希值。时间复杂度O(nO(nO(n logloglog n)n)n)
这个问题可以使用 manacher 算法 在 O(n)O(n)O(n) 的时间内解决。

通过哈希同样可以O(n)O(n)O(n) 解决这个问题,具体方法就是记 RiR_{i}Ri 表示以 iii 作为结尾的最长回文的长度,那么答案就是maxi=1nRimax^{n}_{i=1}R_{i}maxi=1nRi 。考虑到 Ri≤Ri−1+2R_i\leq R_{i-1}+2RiRi1+2,因此我们只需要暴力从 Ri−1+2R_{i-1}+2Ri1+2开始递减,直到找到第一个回文即可。记变量 zzz 表示当前枚举的 RiR_iRi,初始时为0 ,则 zzz 在每次 iii 增大的时候都会增大 2,之后每次暴力循环都会减少1 ,故暴力循环最多发生2n 次,总的时间复杂度为 O(n)。

最长公共子字符串

问题:给定 m 个总长不超过n 的非空字符串,查找所有字符串的最长公共子字符串,如果有多个,任意输出其中一个。其中1≤m,n≤1061\leq m,n\leq10^61m,n106

很显然如果存在长度为k 的最长公共子字符串,那么 k-1 的公共子字符串也必定存在。因此我们可以二分最长公共子字符串的长度。假设现在的长度为k ,check(k) 的逻辑为我们将所有所有字符串的长度为k 的子串分别进行哈希,将哈希值放入 n 个哈希表中存储。之后求交集即可。
时间复杂度为O(nO(nO(n log2log_2log2 nm)\frac{n}{m})mn)

确定字符串中不同子字符串的数量

问题:给定长为n 的字符串,仅由小写英文字母组成,查找该字符串中不同子串的数量。

为了解决这个问题,我们遍历了所有长度为 l=1,...,nl=1,...,nl=1,...,n 的子串。对于每个长度为 lll,我们将其 Hash 值乘以相同的 b 的幂次方,并存入一个数组中。数组中不同元素的数量等于字符串中长度不同的子串的数量,并此数字将添加到最终答案中。
为了方便起见,我们将使用 h[i]h[i]h[i] 作为 Hash 的前缀字符,并定义h[0]=0h[0]=0h[0]=0

字典树 (Trie)

字典树,英文名 trie。顾名思义,就是一个像字典一样的树。
先放一张图:

可以发现,这棵字典树用边来代表字母,而从根结点到树上某一结点的路径就代表了一个字符串。举个例子,1→4→8→121\rightarrow4\rightarrow8\rightarrow1214812 表示的就是字符串 caa。

trie 的结构非常好懂,我们用 δ(u,c)\delta(u,c)δ(u,c) 表示结点uuuccc 字符指向的下一个结点,或着说是结点 uuu 代表的字符串后面添加一个字符 ccc 形成的字符串的结点。( ccc 的取值范围和字符集大小有关,不一定是 000~26。)

有时需要标记插入进 trie 的是哪些字符串,每次插入完成时在这个字符串所代表的节点处打上标记即可。
Phone List POJ - 3630(字典树模板题)

应用

检索字符串

字典树最基础的应用——查找一个字符串是否在“字典”中出现过。
例题:字典树模板+洛谷P2580 于是他错误的点名开始了

AC 自动机

trie 是 AC 自动机 的一部分。

维护异或极值

将数的二进制表示看做一个字符串,就可以建出字符集为{0,1} 的 trie 树。

前缀函数与 KMP 算法
Boyer-Moore算法
Z 函数(扩展 KMP)
自动机

AC 自动机

Keywords Search HDU - 2222(AC自动机模板)

后缀数组 (SA)
后缀自动机 (SAM)
后缀平衡树
广义后缀自动机
后缀树

Manacher

最长回文 HDU - 3068(求最长回文串的长度【马拉车算法Manacher】)

回文树
序列自动机
最小表示法
Lyndon 分解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/309303.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[JavaWeb-Servlet]IDEA与Tomcat的相关配置

IDEA与tomcat的相关配置 1. IDEA会为每一个tomcat部署的项目单独建立一份配置文件* 查看控制台的log&#xff1a;Using CATALINA_BASE: "C:\Users\fqy\.IntelliJIdea2018.1\system\tomcat\_itcast"2. 工作空间项目 和 tomcat部署的web项目* tomcat真正访问…

C#9.0 终于来了,您还学的动吗? 带上VS一起解读吧!

一&#xff1a;背景1. 讲故事好消息&#xff0c;.NET 5.0 终于在2020年6月10日发布了第五个预览版&#xff0c;眼尖的同学一定看到了在这个版本中终于支持了 C# 9.0&#xff0c;此处有掌声&#xff0c;太好了&#xff01;&#xff01;&#xff01;.Net5官方链接可以看到目前的C…

KMP模式串匹配+Compress Words CodeForces - 1200E

题意&#xff1a; 给你若干个字符串&#xff0c;答案串初始为空。第 iii 步将第 iii 个字符串加到答案串的后面&#xff0c;但是尽量地去掉重复部分&#xff08;即去掉一个最长的、是原答案串的后缀、也是第 iii个串的前缀的字符串&#xff09;&#xff0c;求最后得到的字符串…

.NET Core 反射获取所有控制器及方法上特定标签

有个需求&#xff0c;就是在. NET Core中&#xff0c;我们想在项目 启动时&#xff0c;获取LinCmsAuthorizeAttribute这个特性标签所有出现的地方&#xff0c;把他的参数&#xff0c;放入一个集合并缓存起来&#xff0c;以便后面使用此数据用于权限验证。我们通过反射获取所有控…

[JavaWeb-Servlet]Servlet的体系结构

Servlet的体系结构 Servlet -- 接口|GenericServlet -- 抽象类|HttpServlet -- 抽象类* GenericServlet&#xff1a;将Servlet接口中其他的方法做了默认空实现&#xff0c;只将service()方法作为抽象* 将来定义Servlet类时&#xff0c;可以继承GenericServlet&#xff0c;实现…

折半搜索+洛谷 P2962 [USACO09NOV]Lights G

题意&#xff1a; 有 n盏灯&#xff0c;每盏灯与若干盏灯相连&#xff0c;每盏灯上都有一个开关&#xff0c;如果按下一盏灯上的开关&#xff0c;这盏灯以及与之相连的所有灯的开关状态都会改变。一开始所有灯都是关着的&#xff0c;你需要将所有灯打开&#xff0c;求最小的按…

将数据从 SQL Server 导入 Azure Storage Table

点击上方蓝字关注“汪宇杰博客”导语最近有个需求要将数据存储从 SQL Server 数据库切换到 Azure Storage 中的 Table。然而不管是 SSMS 还是 Azure Portal 都没有提供直接的导入功能&#xff0c;是不是又想自己写程序去导数据了&#xff1f;其实不用&#xff01;没有点过数据库…

[JavaWeb-HTTP]HTTP概念

HTTP&#xff1a; * 概念&#xff1a;Hyper Text Transfer Protocol 超文本传输协议* 传输协议&#xff1a;定义了&#xff0c;客户端和服务器端通信时&#xff0c;发送数据的格式* 特点&#xff1a;1. 基于TCP/IP的高级协议2. 默认端口号:803. 基于请求/响应模型的:一次请求对…

Good Number Gym - 102769G 2020年CCPC秦皇岛分站赛

题意&#xff1a; 如果一个数字是Good Number&#xff0c;当且仅当 ⌊xk⌋\left \lfloor\sqrt[k]{x}\right \rfloor⌊kx​⌋(向下取整) 能整除 x 。 现在给出 n,k &#xff0c;求 1 到 n 之中Good Number 的个数。 题目&#xff1a; Alex loves numbers. Alex thinks that…

【完整目录】每天5分钟用C#学习数据结构

【基础知识】| 作者 / Edison Zhou这是恰童鞋骚年的第250篇原创内容不知不觉&#xff0c;每天5分钟学习数据结构就更新完了&#xff0c;本篇将该系列所有文章整理起来作为一个目录&#xff0c;方便你的快速阅读。1线性表线性表是最简单也是在编程当中使用最多的一种数据结构。例…

.NET 5 开发WPF - 美食应用登录UI设计

点击上方“Dotnet9”添加关注哦Demo演示&#xff1a;演示动画你的时间宝贵&#xff0c;不想看啰嗦的文字&#xff0c;可直接拉到文末下载源码&#xff01;1. 新建项目站长开发环境&#xff1a;VS 2019企业版 16.70.NET 5 Preview 5.NET 5 WPF 项目模板和 .NET Core 3.1 WPF 项目…

[JavaWeb-HTTP]HTTP_请求消息_请求头请求体

请求消息数据格式 1. 请求行请求方式 请求url 请求协议/版本GET /login.html HTTP/1.1* 请求方式&#xff1a;* HTTP协议有7中请求方式&#xff0c;常用的有2种* GET&#xff1a;1. 请求参数在请求行中&#xff0c;在url后。2. 请求的url长度有限制的3. 不太安全* POST&#xf…

字典树模板+洛谷P2580 于是他错误的点名开始了

题目&#xff1a; 题目背景 XS中学化学竞赛组教练是一个酷爱炉石的人。 他会一边搓炉石一边点名以至于有一天他连续点到了某个同学两次&#xff0c;然后正好被路过的校长发现了然后就是一顿欧拉欧拉欧拉&#xff08;详情请见已结束比赛 CON900&#xff09;。 题目描述 这之…

基于 abp vNext 和 .NET Core 开发博客项目 - Blazor 实战系列(五)

系列文章使用 abp cli 搭建项目给项目瘦身&#xff0c;让它跑起来完善与美化&#xff0c;Swagger登场数据访问和代码优先自定义仓储之增删改查统一规范API&#xff0c;包装返回模型再说Swagger&#xff0c;分组、描述、小绿锁接入GitHub&#xff0c;用JWT保护你的API异常处理和…

[JavaWeb-Servlet]概述与快速入门

Servlet&#xff1a; server applet * 概念&#xff1a;运行在服务器端的小程序* Servlet就是一个接口&#xff0c;定义了Java类被浏览器访问到(tomcat识别)的规则。* 将来我们自定义一个类&#xff0c;实现Servlet接口&#xff0c;复写方法。* 快速入门&#xff1a;1. 创建Ja…

01tire+洛谷P4551 最长异或路径

题目&#xff1a; 给定一棵n个点的带权树&#xff0c;结点下标从1开始到N。寻找树中找两个结点&#xff0c;求最长的异或路径。 异或路径指的是指两个结点之间唯一路径上的所有边权的异或。 输入格式 第一行一个整数NN&#xff0c;表示点数。 接下来 n−1 行&#xff0c;给…

C#9.0 终于来了,带你一起解读 nint 和 Pattern matching 两大新特性玩法

一&#xff1a;背景1. 讲故事上一篇C#9.0 终于来了&#xff0c;您还学的动吗&#xff1f; 带上VS一起解读吧&#xff01;跟大家聊到了Target-typed new 和 Lambda discard parameters&#xff0c;看博客园和公号里的阅读量都达到了新高&#xff0c;甚是欣慰&#xff0c;不管大家…

[JavaWeb-Tomcat]web服务器软件_Tomcat介绍

Tomcat&#xff1a;web服务器软件 1. 下载&#xff1a;http://tomcat.apache.org/2. 安装&#xff1a;解压压缩包即可。* 注意&#xff1a;安装目录建议不要有中文和空格3. 卸载&#xff1a;删除目录就行了4. 启动&#xff1a;* bin/startup.bat ,双击运行该文件即可* 访问&…

软件设计模式期末大作业——可乐商城管理系统

文章目录设计模式大作业软 件 设 计 模 式 任 务 书设计要求&#xff1a;学生应完成的工作&#xff1a;1. 应用场景描述2. 设计模式选择3. 实现语言与工具参考文献阅读&#xff1a;工作计划&#xff1a;一、系统目标1. 设计目的2. 需求描述二、 系统模式选择1.需求分析2.选用设…

深度解读Microsoft Build 2020:提升开发效率,优化开发环境

Microsoft Build 2020在众多新产品与技术发布中圆满落幕但身为开发技术人深知技术世界的更迭、求索却从未止步唯有不断提升自身技能栈创新方能从技术浮沉中获得更多养分让技术予力世界更有温度Microsoft Build 2020大会后&#xff0c; Visual Studio Family 和 .NET 成为众多开…