【SSL_1137】字符串

本文介绍了一道算法题,目标是计算一个字符串中包含特定子串bear的所有可能子串的数量。通过分析样例,提出了一个O(N^2)的解题思路,并给出了C++实现代码。

字符串


题目描述

小熊有一个由小写英文字母组成的字符串s = s1s2…sn。小熊想要计算s中有多少子串包含字符串“bear”,也就是找出满足字符串x(i, j)= sisi+1…sj 包含至少一个字符串“bear”的 (i, j)对数(1≤i≤j≤n)。

字符串x(i, j)包含字符串“bear”定义为存在一个整数k(i≤k≤j-3),满足sk=b,sk+1=e,sk+2=a,sk+3=r。

请帮助小熊解决这个问题。

输入

输入共1行,包含一个非空字符串s。数据保证字符串s中只包含小写英文字母。

输出

输出共1行,包含一个整数,表示这个问题的答案。

输入样例

bebearar

输出样例

9

说明

【输入输出样例说明】
符合条件的9对(i, j)为:(1,6),(1,7),(1,8),(2,6),(2,7),(2,8),(3,6),(3,7),(3,8)。
【数据说明】
对于50%的数据,1≤n≤200。
对于100%的数据,1≤n≤3000。

解题思路

我们可以先研究一下样例:(1,6),(1,7),(1,8),(2,6),(2,7),(2,8),(3,6),(3,7),(3,8)(1,6),(1,7),(1,8),(2,6),(2,7),(2,8),(3,6),(3,7),(3,8)(16)(17)(18)(26)(27)(28)(36)(37)(38)
而bear的末端的下标是6(下标从1开始的情况),所以我们可以发现:从 “r” 到结尾的所有点都可以成为子串的右端。

那么我们就可以研究出一个 O(N2) 的暴力 (憨批) 算法,代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

long long n,ans;
char a[3010];
char t[4]={'b','e','a','r'};

int main()
{
	cin>>a;
	n=strlen(a);
	for(int i=0;i<n;i++)
		for(int j=i;j<n;j++)
			if(a[j]=='b'&&a[j+1]=='e'&&a[j+2]=='a'&&a[j+3]=='r')
			{
				ans+=n-j-3;
				break;
			}
	cout<<ans<<endl;
}
<think>我们需要修改文件匹配逻辑:原先是根据固定格式“日期_待发送文件_机构代码.xlsx”来构建文件名,现在改为“日期_固定字符串_随机字符串_机构代码.xlsx”。由于随机字符串的存在,我们无法直接通过构建文件名来获取文件,因此需要遍历目录中的文件,并解析出机构代码。 修改思路: 1. 遍历当日目录下的所有.xlsx文件。 2. 解析文件名,按照“日期_固定字符串_随机字符串_机构代码.xlsx”的格式拆分,提取机构代码。 3. 注意:日期部分格式为YYYYMMDD,固定字符串是已知的(比如"待发送文件"),但随机字符串是任意字符串(不含下划线),机构代码在最后一部分(去掉扩展名)。 步骤: 1. 获取当日目录下的所有文件。 2. 遍历每个文件,检查文件名是否以日期开头,并且含已知的固定字符串(例如"待发送文件"),然后提取机构代码部分。 3. 构建一个字典,将机构代码映射到其对应的文件路径。 然后,在发送每个机构时,根据机构代码从该字典中查找对应的文件。 注意:由于文件名中有随机字符串,我们不能直接通过拼接字符串得到文件名,而是需要根据模式去匹配。 修改后的代码部分: 在函数`send_emails`中,我们将改变获取附件文件的方式: 1. 首先,我们构建一个字典`org_attachments`,用于存储机构代码对应的文件路径。 2. 遍历当日目录下的所有文件,对每个文件尝试解析: - 检查文件扩展名是否为.xlsx - 拆分文件名(不带扩展名)用下划线分割 - 文件名应该至少有4部分:日期、固定字符串、随机字符串、机构代码 - 我们已知固定字符串(例如"待发送文件"),但这里我们可以不验证随机字符串,只验证日期和固定字符串,然后取最后一部分作为机构代码。 假设固定字符串为"待发送文件",则文件名格式为: [日期]_待发送文件_[随机字符串]_[机构代码].xlsx 注意:由于随机字符串中可能含下划线?但根据问题描述,我们假设文件名结构是明确的四部分,所以随机字符串本身不含下划线。如果随机字符串可能含下划线,那么我们就不能简单地用下划线分割。因此,我们需要更明确的要求:随机字符串含下划线,这样就能确保分割后是四部分。 但是,如果随机字符串可能含下划线,那么我们就需要改变策略:固定字符串是已知的,我们可以用固定字符串作为锚点,然后取固定字符串之后的部分直到倒数第二部分为随机字符串(但这样不可靠),或者我们要求机构代码是已知的(在org_recipients的键中),然后检查文件名是否以机构代码结尾。 更稳健的做法: 由于机构代码是已知的(在org_recipients的键中),我们可以遍历每个机构代码,然后检查目录中是否存在一个文件,其文件名含该机构代码,并且以日期开头,并且含固定字符串。 但这样效率较低,因为每个机构都要扫描一次目录。 因此,我们假设文件名分割后,机构代码是最后一部分(去掉扩展名后的最后一部分),且随机字符串含下划线。 具体步骤: 1. 遍历当日目录下的所有文件: for file in os.listdir(attachment_dir): if file.endswith('.xlsx'): parts = file.split('.')[0].split('_') # 去掉扩展名,分割 # 我们期望至少4部分: [日期, 固定字符串, 随机字符串, 机构代码] if len(parts) < 4: continue # 检查日期部分是否匹配当日 if parts[0] != today: continue # 检查固定字符串是否匹配(假设固定字符串为"待发送文件") if parts[1] != '待发送文件': continue # 那么机构代码就是最后一部分 org_code = parts[-1] # 随机字符串就是parts[2](如果还有更多下划线,那么随机字符串是parts[2:-1]的合并?但题目要求是四部分,所以这里应该是parts[2]) # 但是,如果文件名是“日期_固定字符串_随机字符串_机构代码”,那么应该是4部分,所以索引0:日期,1:固定字符串2:随机字符串,3:机构代码 # 因此,我们取parts[3]作为机构代码?不,因为分割后是4部分,所以索引0,1,2,3,那么机构代码是parts[3]。 # 但是,如果随机字符串含下划线,那么分割后就会超过4部分,这样就不符合要求。因此我们要求随机字符串不能含下划线。 # 所以,我们只处理分割后恰好4部分的情况?或者我们允许固定字符串后的所有部分直到倒数第二为随机字符串?不,题目要求是四部分。 # 因此,我们只取分割后为4部分的情况: if len(parts) == 4: # 机构代码就是parts[3] org_attachments[org_code] = os.path.join(attachment_dir, file) 2. 然后,在发送机构邮件时,我们根据机构代码从org_attachments中获取文件路径。 但是,注意:一个机构代码可能对应多个文件?根据题目描述,每个机构只有一个文件(文件名中含机构代码),所以我们可以这样处理。 修改后的函数代码: 我们将改变文件获取方式,不再直接构建文件名,而是通过扫描目录来建立机构代码到文件路径的映射。 注意:如果目录中有多个文件匹配同一个机构代码,那么这里会以最后扫描到的文件为准。为了避免这种情况,我们可以检查是否已经存在该机构代码的文件,如果存在则报错。 因此,我们可以在扫描时检查重复。 修改后的代码: 在函数`send_emails`中,在验证附件目录存在之后,我们扫描目录构建映射: ```python # 扫描目录,构建机构代码到文件路径的映射 org_attachments = {} # 机构代码: 文件路径 for filename in os.listdir(attachment_dir): if filename.endswith('.xlsx'): # 去掉扩展名,分割 name_without_ext = filename.rsplit('.', 1)[0] parts = name_without_ext.split('_') # 检查是否至少4部分 if len(parts) < 4: continue # 检查日期部分 if parts[0] != today: continue # 检查固定字符串(假设固定字符串为"待发送文件") if parts[1] != '待发送文件': continue # 取最后一部分作为机构代码 org_code = parts[-1] # 检查机构代码是否在收件人字典的键中(可选,但可以避免发送无关机构) # 注意:如果不在,我们可以跳过,但这里我们不管,先收集起来。 # 如果同一个机构代码出现多次,我们只保留最后一个(或者报错) if org_code in org_attachments: print("警告: 机构代码 {0} 有多个文件,将使用最新匹配的文件".format(org_code)) # 或者根据需求,可以记录错误并跳过 # 这里我们选择覆盖 org_attachments[org_code] = os.path.join(attachment_dir, filename) ``` 然后,在遍历机构时,我们使用这个映射来获取文件路径: ```python for org_code, recipient_list in org_recipients.items(): # 检查是否达到30人限额 if total_sent + len(recipient_list) > 30: print("已达到30人限额,终止当前会话") break # 查找该机构的附件 if org_code not in org_attachments: print("跳过机构 {0}: 没有找到对应的文件".format(org_code)) continue file_path = org_attachments[org_code] # 再次检查文件是否存在(应该存在,因为是从目录中扫描的) if not os.path.exists(file_path): print("跳过机构 {0}: 文件不存在 {1}".format(org_code, file_path)) continue # 然后继续发送流程... ``` 注意:固定字符串"待发送文件"在代码中写死了,如果以后需要改变,可以设为配置变量。 修改后的完整代码(针对Python 3.4):</think>以下是针对新文件名结构(`日期_固定字符串_随机字符串_机构代码.xlsx`)修改后的Python脚本。主要修改点在于文件匹配逻辑,使用正则表达式提取机构代码: ```python import os import re import smtplib import ssl from email.mime.multipart import MIMEMultipart from email.mime.base import MIMEBase from email.mime.text import MIMEText from email import encoders from datetime import datetime # ===== 配置区域 ===== SMTP_SERVER = 'smtp.example.com' # SMTP服务器地址 SMTP_PORT = 465 # SSL端口 SENDER_EMAIL = 'your_email@example.com' # 发件邮箱 SENDER_PASSWORD = 'your_password' # 邮箱密码/授权码 BASE_DIR = '/path/to/attachments' # 附件存储基础目录 FIXED_STRING = '固定字符串' # 文件名中的固定部分 # ==================== def find_attachment_files(today_dir): """ 在目录中查找匹配模式的文件并返回机构代码到文件路径的映射 :param today_dir: 当日文件目录 :return: 字典 {机构代码: 文件路径} """ file_map = {} # 构建文件名匹配的正则表达式 # 模式: 日期_固定字符串_随机字符串_机构代码.xlsx pattern = re.compile(r'^{0}_{1}_[^_]+_(.+?)\.xlsx$'.format( re.escape(datetime.now().strftime("%Y%m%d")), re.escape(FIXED_STRING) )) # 遍历目录中的所有文件 for filename in os.listdir(today_dir): match = pattern.match(filename) if match: org_code = match.group(1) file_path = os.path.join(today_dir, filename) # 检查机构代码是否已存在映射中 if org_code in file_map: print("警告: 机构 {0} 有多个匹配文件,使用 {1}".format( org_code, filename)) file_map[org_code] = file_path return file_map def send_emails(org_recipients): """ 发送邮件主函数 :param org_recipients: 机构收件人字典 {机构代码: [邮箱列表]} """ # 获取当日日期格式 YYYYMMDD today = datetime.now().strftime("%Y%m%d") attachment_dir = os.path.join(BASE_DIR, today) # 验证附件目录是否存在 if not os.path.exists(attachment_dir): print("错误: 附件目录不存在 {0}".format(attachment_dir)) return # 查找所有匹配的附件文件 attachment_map = find_attachment_files(attachment_dir) # 创建SSL安全上下文 context = ssl.create_default_context() # 分批发送控制变量 total_sent = 0 batch_count = 0 # 遍历所有机构 for org_code, recipient_list in org_recipients.items(): # 检查是否达到30人限额 if total_sent + len(recipient_list) > 30: print("已达到30人限额,终止当前会话") break # 获取该机构的附件文件路径 file_path = attachment_map.get(org_code) if not file_path: print("跳过机构 {0}: 未找到匹配文件".format(org_code)) continue if not os.path.exists(file_path): print("跳过机构 {0}: 文件不存在 {1}".format(org_code, file_path)) continue try: # 每批首次发送时创建SMTP连接 if batch_count == 0: server = smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT, context=context) server.login(SENDER_EMAIL, SENDER_PASSWORD) print("\n===== 创建新SMTP会话 =====") # 创建邮件对象 msg = MIMEMultipart() msg['From'] = SENDER_EMAIL msg['To'] = ", ".join(recipient_list) # 多个收件人 msg['Subject'] = "{0} {1} 机构文件".format(today, org_code) # 添加邮件正文 body = "请查收附件中的{0}机构数据文件。".format(org_code) msg.attach(MIMEText(body, 'plain')) # 添加附件 with open(file_path, "rb") as attachment: part = MIMEBase("application", "octet-stream") part.set_payload(attachment.read()) encoders.encode_base64(part) # 获取原始文件名用于附件头 filename = os.path.basename(file_path) part.add_header( "Content-Disposition", "attachment; filename={0}".format(filename), ) msg.attach(part) # 发送邮件 server.sendmail(SENDER_EMAIL, recipient_list, msg.as_string()) print("发送成功: {0} -> {1}位收件人".format(org_code, len(recipient_list))) # 更新计数 total_sent += len(recipient_list) batch_count += 1 # 达到30人时关闭当前会话 if total_sent >= 30: server.quit() print("已关闭SMTP会话(达到限额)") batch_count = 0 except Exception as e: print("发送失败 {0}: {1}".format(org_code, str(e))) # 关闭最终会话(如果未达限额) if batch_count > 0: server.quit() print("已关闭SMTP会话(批次完成)") # 示例收件人字典 org_recipients_example = { 'ORG001': ['rec1@example.com', 'rec2@example.com'], 'ORG002': ['rec3@example.com', 'rec4@example.com'], # ... 其他机构数据 } if __name__ == "__main__": send_emails(org_recipients_example) ``` ### 主要修改说明: 1. **新增文件查找函数**: ```python def find_attachment_files(today_dir): # 构建正则表达式模式 pattern = re.compile(r'^{0}_{1}_[^_]+_(.+?)\.xlsx$'.format( re.escape(datetime.now().strftime("%Y%m%d")), re.escape(FIXED_STRING) )) # 遍历并匹配文件 for filename in os.listdir(today_dir): match = pattern.match(filename) if match: org_code = match.group(1) # 提取机构代码 file_map[org_code] = os.path.join(today_dir, filename) ``` 2. **正则表达式模式详解**: - `^{0}`:以日期开头 - `_{1}_`:固定字符串部分(需要配置) - `[^_]+`:随机字符串(不含下划线) - `_(.+?)`:机构代码部分(捕获组) - `\.xlsx$`:以.xlsx结尾 3. **文件映射处理**: - 创建 `attachment_map` 字典:`{机构代码: 文件路径}` - 发送前通过机构代码查找文件路径: ```python file_path = attachment_map.get(org_code) ``` 4. **配置项新增**: ```python FIXED_STRING = '固定字符串' # 必须与实际文件名中的固定部分一致 ``` ### 正则表达式匹配逻辑说明: 1. **日期部分**: - `{0}` 对应 `datetime.now().strftime("%Y%m%d")` - `re.escape()` 确保特殊字符被转义 2. **固定字符串**: - `{1}` 对应配置的 `FIXED_STRING` - 同样使用 `re.escape()` 处理特殊字符 3. **随机字符串**: - `[^_]+` 匹配一个或多个非下划线字符 - 确保不会错误匹配含下划线的部分 4. **机构代码捕获**: - `_(.+?)` 匹配下划线后的机构代码 - `(.+?)` 非贪婪匹配确保只捕获到扩展名前 ### 使用注意事项: 1. **文件名要求**: - 随机字符串不能含下划线(否则会错误匹配) - 机构代码必须是文件名最后一部分(扩展名前) 2. **多文件处理**: - 同一机构多个文件时,只使用最后匹配的文件 - 可通过修改 `find_attachment_files` 处理多文件情况 3. **正则表达式灵活性**: - 如需处理更复杂的文件名,可调整正则表达式: ```python # 允许随机字符串含下划线(但需确保机构代码是最后一部分) pattern = re.compile(r'^{0}_{1}_.+?_(.+?)\.xlsx$'.format(...)) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值