当前位置: 首页 > news >正文

【华为OD】环中最长子串2

【华为OD】环中最长子串2

题目描述

给你一个字符串s,字符串 s 首尾相连成一个环形,请你在环中找出"l"、“o”、"x"字符都恰好出现了偶数次最长子字符串的长度。

输入描述

输入是一串小写的字母组成的字符串。

输出描述

输出是一个整数。

示例

输入:

alolobo

输出:

6

说明:
最长子字符串之一是"alolob",它包含"l",“o"各2个,以及0个"x”。

解题思路

这是一个环形字符串中寻找满足特定条件的最长子串问题。关键在于:

  1. 字符串是环形的,需要考虑跨越首尾的情况
  2. 需要找到"l"、“o”、"x"三个字符都出现偶数次的最长子串
  3. 使用状态压缩和前缀和的思想来优化

核心思想:

  • 使用位运算表示三个字符的奇偶性状态
  • 利用前缀异或和的性质:如果两个位置的状态相同,那么它们之间的子串中三个字符都出现了偶数次
  • 考虑环形结构,将字符串复制一份来处理跨越边界的情况

我将提供两种解法:暴力枚举法状态压缩 + 前缀异或优化法

解法一:暴力枚举法

枚举所有可能的子串,统计每个子串中"l"、“o”、"x"的出现次数,判断是否都为偶数。

Java实现

import java.util.*;public class Solution1 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);String s = sc.nextLine();sc.close();int n = s.length();int maxLen = 0;// 为了处理环形,将字符串复制一份String doubled = s + s;// 枚举所有可能的起始位置for (int start = 0; start < n; start++) {int countL = 0, countO = 0, countX = 0;// 枚举以start为起点的所有子串for (int len = 1; len <= n; len++) {int pos = (start + len - 1) % n;char c = s.charAt(pos);// 更新字符计数if (c == 'l') countL++;else if (c == 'o') countO++;else if (c == 'x') countX++;// 检查是否满足条件(三个字符都出现偶数次)if (countL % 2 == 0 && countO % 2 == 0 && countX % 2 == 0) {maxLen = Math.max(maxLen, len);}}}System.out.println(maxLen);}
}

Python实现

def solve_brute_force():s = input().strip()n = len(s)max_len = 0# 枚举所有可能的起始位置for start in range(n):count_l = count_o = count_x = 0# 枚举以start为起点的所有子串for length in range(1, n + 1):pos = (start + length - 1) % nc = s[pos]# 更新字符计数if c == 'l':count_l += 1elif c == 'o':count_o += 1elif c == 'x':count_x += 1# 检查是否满足条件(三个字符都出现偶数次)if count_l % 2 == 0 and count_o % 2 == 0 and count_x % 2 == 0:max_len = max(max_len, length)print(max_len)solve_brute_force()

C++实现

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;int main() {string s;cin >> s;int n = s.length();int maxLen = 0;// 枚举所有可能的起始位置for (int start = 0; start < n; start++) {int countL = 0, countO = 0, countX = 0;// 枚举以start为起点的所有子串for (int len = 1; len <= n; len++) {int pos = (start + len - 1) % n;char c = s[pos];// 更新字符计数if (c == 'l') countL++;else if (c == 'o') countO++;else if (c == 'x') countX++;// 检查是否满足条件(三个字符都出现偶数次)if (countL % 2 == 0 && countO % 2 == 0 && countX % 2 == 0) {maxLen = max(maxLen, len);}}}cout << maxLen << endl;return 0;
}

解法二:状态压缩 + 前缀异或优化法

使用位运算来表示三个字符的奇偶性状态,利用前缀异或和的性质来快速判断子串是否满足条件。

Java实现

import java.util.*;public class Solution2 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);String s = sc.nextLine();sc.close();int n = s.length();int maxLen = 0;// 状态压缩:用3位二进制表示l、o、x的奇偶性// 第0位表示l,第1位表示o,第2位表示x// 0表示偶数次,1表示奇数次// 记录每个状态第一次出现的位置Map<Integer, Integer> statePos = new HashMap<>();statePos.put(0, -1); // 初始状态,所有字符都出现0次(偶数次)int state = 0;// 处理环形:遍历两倍长度for (int i = 0; i < 2 * n; i++) {char c = s.charAt(i % n);// 更新状态if (c == 'l') state ^= 1;      // 第0位异或else if (c == 'o') state ^= 2; // 第1位异或else if (c == 'x') state ^= 4; // 第2位异或if (statePos.containsKey(state)) {// 找到相同状态,计算子串长度int len = i - statePos.get(state);if (len <= n) { // 确保不超过原字符串长度maxLen = Math.max(maxLen, len);}} else {statePos.put(state, i);}}System.out.println(maxLen);}
}

Python实现

def solve_optimized():s = input().strip()n = len(s)max_len = 0# 状态压缩:用3位二进制表示l、o、x的奇偶性# 第0位表示l,第1位表示o,第2位表示x# 0表示偶数次,1表示奇数次# 记录每个状态第一次出现的位置state_pos = {0: -1}  # 初始状态,所有字符都出现0次(偶数次)state = 0# 处理环形:遍历两倍长度for i in range(2 * n):c = s[i % n]# 更新状态if c == 'l':state ^= 1      # 第0位异或elif c == 'o':state ^= 2      # 第1位异或elif c == 'x':state ^= 4      # 第2位异或if state in state_pos:# 找到相同状态,计算子串长度length = i - state_pos[state]if length <= n:  # 确保不超过原字符串长度max_len = max(max_len, length)else:state_pos[state] = iprint(max_len)solve_optimized()

C++实现

#include <iostream>
#include <string>
#include <unordered_map>
#include <algorithm>
using namespace std;int main() {string s;cin >> s;int n = s.length();int maxLen = 0;// 状态压缩:用3位二进制表示l、o、x的奇偶性// 第0位表示l,第1位表示o,第2位表示x// 0表示偶数次,1表示奇数次// 记录每个状态第一次出现的位置unordered_map<int, int> statePos;statePos[0] = -1; // 初始状态,所有字符都出现0次(偶数次)int state = 0;// 处理环形:遍历两倍长度for (int i = 0; i < 2 * n; i++) {char c = s[i % n];// 更新状态if (c == 'l') state ^= 1;      // 第0位异或else if (c == 'o') state ^= 2; // 第1位异或else if (c == 'x') state ^= 4; // 第2位异或if (statePos.find(state) != statePos.end()) {// 找到相同状态,计算子串长度int len = i - statePos[state];if (len <= n) { // 确保不超过原字符串长度maxLen = max(maxLen, len);}} else {statePos[state] = i;}}cout << maxLen << endl;return 0;
}

解法三:优化的环形处理方案

考虑到环形的特殊性,提供一个更清晰的处理方案:

Java实现

import java.util.*;public class Solution3 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);String s = sc.nextLine();sc.close();int n = s.length();int maxLen = 0;// 方法1:直接在原字符串上处理环形for (int start = 0; start < n; start++) {Map<Integer, Integer> statePos = new HashMap<>();statePos.put(0, start - 1);int state = 0;for (int i = 0; i < n; i++) {int pos = (start + i) % n;char c = s.charAt(pos);if (c == 'l') state ^= 1;else if (c == 'o') state ^= 2;else if (c == 'x') state ^= 4;if (statePos.containsKey(state)) {int len = start + i - statePos.get(state);maxLen = Math.max(maxLen, len);} else {statePos.put(state, start + i);}}}System.out.println(maxLen);}
}

Python实现

def solve_circular():s = input().strip()n = len(s)max_len = 0# 方法1:直接在原字符串上处理环形for start in range(n):state_pos = {0: start - 1}state = 0for i in range(n):pos = (start + i) % nc = s[pos]if c == 'l':state ^= 1elif c == 'o':state ^= 2elif c == 'x':state ^= 4if state in state_pos:length = start + i - state_pos[state]max_len = max(max_len, length)else:state_pos[state] = start + iprint(max_len)solve_circular()

C++实现

#include <iostream>
#include <string>
#include <unordered_map>
#include <algorithm>
using namespace std;int main() {string s;cin >> s;int n = s.length();int maxLen = 0;// 方法1:直接在原字符串上处理环形for (int start = 0; start < n; start++) {unordered_map<int, int> statePos;statePos[0] = start - 1;int state = 0;for (int i = 0; i < n; i++) {int pos = (start + i) % n;char c = s[pos];if (c == 'l') state ^= 1;else if (c == 'o') state ^= 2;else if (c == 'x') state ^= 4;if (statePos.find(state) != statePos.end()) {int len = start + i - statePos[state];maxLen = max(maxLen, len);} else {statePos[state] = start + i;}}}cout << maxLen << endl;return 0;
}

算法复杂度分析

解法一:暴力枚举法

  • 时间复杂度:O(N²),需要枚举所有可能的子串
  • 空间复杂度:O(1)

解法二:状态压缩 + 前缀异或优化法

  • 时间复杂度:O(N),只需要遍历字符串
  • 空间复杂度:O(1),状态数量最多8种(2³)

解法三:优化的环形处理方案

  • 时间复杂度:O(N²),但常数较小
  • 空间复杂度:O(1)

算法原理详解

状态压缩的核心思想

使用3位二进制数来表示"l"、“o”、"x"三个字符的奇偶性状态:

  • 第0位:'l’字符的奇偶性(0=偶数,1=奇数)
  • 第1位:'o’字符的奇偶性(0=偶数,1=奇数)
  • 第2位:'x’字符的奇偶性(0=偶数,1=奇数)

前缀异或的性质

如果两个位置的状态相同,说明从第一个位置到第二个位置之间的子串中,三个字符都出现了偶数次。

这是因为:state[j] = state[i] 意味着 state[i] ^ state[j] = 0,而 state[i] ^ state[j] 正好表示区间 [i+1, j] 中三个字符的奇偶性。

环形处理

对于环形字符串,有两种处理方式:

  1. 将字符串复制一份,变成长度为2n的线性字符串
  2. 对每个起始位置分别处理,使用取模运算处理环形索引

示例分析

对于输入 "alolobo"

使用状态压缩方法分析:

  • 初始状态:000(l=0, o=0, x=0)
  • 处理’a’:状态不变,仍为000
  • 处理’l’:状态变为001(l=1, o=0, x=0)
  • 处理’o’:状态变为011(l=1, o=1, x=0)
  • 处理’l’:状态变为010(l=0, o=1, x=0)
  • 处理’o’:状态变为000(l=0, o=0, x=0)
  • 处理’b’:状态不变,仍为000
  • 处理’o’:状态变为010(l=0, o=1, x=0)

在位置4时,状态回到000,与初始状态相同,说明子串"alolo"中三个字符都出现偶数次,长度为5。
继续分析可以找到长度为6的子串"alolob"。

总结

三种解法各有特点:

  1. 暴力枚举法:思路直观,容易理解,但时间复杂度较高
  2. 状态压缩 + 前缀异或优化法:最优解法,利用位运算和异或的性质,时间复杂度O(N)
  3. 优化的环形处理方案:在状态压缩基础上优化环形处理逻辑

对于这道题目,推荐使用状态压缩 + 前缀异或优化法,它不仅时间效率最高,而且充分利用了问题的数学性质。

关键技巧:

  • 使用位运算表示字符的奇偶性状态
  • 利用异或运算的性质:a ^ a = 0
  • 通过状态相同来判断区间内字符出现偶数次
  • 合理处理环形字符串的边界情况

文章转载自:

http://6f3Tnukl.Lcqrf.cn
http://uK9YI21s.Lcqrf.cn
http://a53IlE1g.Lcqrf.cn
http://2xGobR3D.Lcqrf.cn
http://mF66NCWq.Lcqrf.cn
http://kF0DszfI.Lcqrf.cn
http://XTAU0ne0.Lcqrf.cn
http://2x12ArHx.Lcqrf.cn
http://4tnZM8f6.Lcqrf.cn
http://eBhHip4p.Lcqrf.cn
http://obE5P5O4.Lcqrf.cn
http://Tv4hZoVO.Lcqrf.cn
http://sJnCci2i.Lcqrf.cn
http://3su8LuDA.Lcqrf.cn
http://rvS4LRju.Lcqrf.cn
http://V1FfsOT7.Lcqrf.cn
http://6A6mlqKm.Lcqrf.cn
http://AL61IKGc.Lcqrf.cn
http://fKzxwNTp.Lcqrf.cn
http://cjlRn8av.Lcqrf.cn
http://rxU1bXlx.Lcqrf.cn
http://ZAGvVAog.Lcqrf.cn
http://LLBUJEXE.Lcqrf.cn
http://JM11gg0q.Lcqrf.cn
http://eGdnW8yU.Lcqrf.cn
http://GXI0L6hp.Lcqrf.cn
http://Ck1rRUJK.Lcqrf.cn
http://EGQGJ4nh.Lcqrf.cn
http://bHe9bBsw.Lcqrf.cn
http://OVR1udgI.Lcqrf.cn
http://www.dtcms.com/a/374436.html

相关文章:

  • 08 docker搭建大数据集群
  • 【华为OD】微服务的集成测试
  • Tool | UI/BI类网址收录
  • 计算机视觉(opencv)——基于模板匹配的身份证号识别系统
  • 腾讯推出AI CLI工具CodeBuddy,国内首家同时支持插件、IDE和CLI三种形态的AI编程工具厂商
  • 前后端联调时出现的一些问题记录
  • 网络编程;套接字;TCP通讯;UDP通讯;0909
  • 最后一公里文件传输难题Localsend+cpolar破解
  • Windows 命令行:cd 命令3,当前目录,父目录,根目录
  • 医疗连续体机器人模块化控制界面设计与Python库应用研究(下)
  • Nginx 优化与防盗链
  • Spring Web 异步响应实战:从 CompletableFuture 到 ResponseBodyEmitter 的全链路优化
  • Linux基础命令使用
  • 第二章、PyTorch 入门笔记:从张量基本操作到线性回归实战
  • 【参数详解与使用指南】PyTorch MNIST数据集加载
  • Ruoyi-vue-plus-5.x第六篇Web开发与前后端交互: 6.4 WebSocket实时通信
  • vlan(局部虚拟网)
  • MissionPlanner架构梳理之(十)-参数编辑器
  • Hadoop Windows客户端配置与实践指南
  • 【NVIDIA-B200】 ‘CUDA driver version is insufficient for CUDA runtime version‘
  • 从源码视角全面解析 Chrome UI 布局系统及 Views 框架的定制化实现方法与实践经验
  • 9.9 ajax的请求和封装
  • CTFshow系列——PHP特性Web101-104
  • MCP学习一——UV安装使用教程
  • 【Java实战㊳】Spring Boot实战:从打包到监控的全链路攻略
  • Go语言实战案例-开发一个Markdown转HTML工具
  • idea、服务器、数据库环境时区不一致问题
  • HarmonyOS 5.1.1版本图片上传功能
  • 2025最新超详细FreeRTOS入门教程:第八章 FreeRTOS任务通知
  • Puter+CPolar低成本替代商业网盘,打造私有云新势力