2023-04-13:给定一个字符串数组strs,其中每个字符串都是小写字母组成的, 如果i < j,并且strs[i]和strs[j]所有的字符随意去排列能组成回文串, 那么说(i,j)叫做一个互补
2023-04-13:给定一个字符串数组strs,其中每个字符串都是小写字母组成的,
如果i < j,并且strs[i]和strs[j]所有的字符随意去排列能组成回文串,
那么说(i,j)叫做一个互补对(complementary)。
求strs中有多少个互补对。
strs长度 <= 3 * 10^5,
单个字符串长度 <= 10^5,
strs里所有字符串总长度 <= 10^6。
来自亚马逊。
答案2023-04-13:
这道题有两种算法:
算法一
该算法使用暴力方法,时间复杂度为 O(N^2*M),其中,N 表示字符串数组的长度,M 表示单个字符串的平均长度。空间复杂度为 O(1)。
算法过程如下:
- 遍历每对字符串(i,j),其中 i<j。
- 判断字符串 strs[i] 和 strs[j] 是否可以组成回文串。
- 如果可以组成回文串,则互补对数加一。
判断字符串是否可以组成回文串的过程如下:
- 统计字符串中每个字符出现的次数。
- 如果某个字符出现了奇数次,则不能组成回文串,返回 false。
- 如果所有字符都出现了偶数次,或只有一个字符出现了奇数次,则可以组成回文串,返回 true。
算法二
基于状态压缩的哈希表方法,通常也称为“状态压缩 + 哈希表”算法。该算法可以有效地避免枚举所有可能的字符串排列组合,从而实现了较优的时间复杂度。
该算法时间复杂度为 O(N*M),其中,N 表示字符串数组的长度,M 表示单个字符串的平均长度。空间复杂度为 O(N)。其中,空间复杂度主要来自于 status 哈希表的存储。
算法过程如下:
- 初始化 hash map status,用于统计每种状态下的字符串数量。
- 遍历每个字符串 str。
- 计算字符串 str 的状态 cur,即将字符串中每个字符对应的二进制位取反后进行异或操作得到的结果。
- 将 status 中 cur 对应的字符串数量加到答案 ans 上。
- 遍历每个字符 ch,将 cur 取反后在第 ch 位上的值,即 (cur ^ (1 << ch)),对应的字符串数量加到答案 ans 上。
- 将 cur 加入 status 中。
计算状态 cur 的过程如下:
- 初始化变量 cur 为 0。
- 遍历字符串 str 中的每个字符 ch。
- 将 ch 对应的二进制位取反,即 (1 << (ch as usize - ‘a’ as usize))。
- 将上一步得到的结果与 cur 进行异或操作。
补充说明:该算法的思路是通过统计字符串中每个字符出现的奇偶次数,将字符串转化成一个状态值。如果两个字符串可以组成互补对,那么它们的状态值必须相同或者只有一位不同。因此,我们遍历所有字符串,用 hash map 统计每种状态值的出现次数,并统计能够产生互补对的字符串数量。
rust完整代码如下:
use std::collections::HashMap;
// 暴力方法
// 时间复杂度O(N^2 * M),N字符串长,M字符串平均长度
fn num1(strs: &[String]) -> usize {
let mut ans = 0;
for i in 0..strs.len() {
for j in (i + 1)..strs.len() {
if complementary(&strs[i], &strs[j]) {
ans += 1;
}
}
}
ans
}
fn complementary(a: &str, b: &str) -> bool {
let mut cnt: [usize; 26] = [0; 26];
for ch in a.chars() {
let idx = ch as usize - 'a' as usize;
cnt[idx] += 1;
}
for ch in b.chars() {
let idx = ch as usize - 'a' as usize;
cnt[idx] += 1;
}
let odd = cnt.iter().filter(|&&num| num % 2 != 0).count();
odd < 2
}
// 正式方法
// O(N*M),N字符串长,M字符串平均长度
// 时间复杂度O(N) + O(M),一共有多少个字符串N,一共有多少字符M
fn num2(strs: &[String]) -> usize {
let mut status: HashMap<usize, usize> = HashMap::new();
let mut ans = 0;
for str in strs {
let cur = str
.chars()
.fold(0, |acc, ch| acc ^ (1 << (ch as usize - 'a' as usize)));
ans += status.get(&cur).unwrap_or(&0);
for i in 0..26 {
ans += status.get(&(cur ^ (1 << i))).unwrap_or(&0);
}
status.entry(cur).and_modify(|cnt| *cnt += 1).or_insert(1);
}
ans
}
// 为了验证
fn random_string_array(n: usize, m: usize, r: usize) -> Vec<String> {
let mut ans = vec![];
for _ in 0..n {
let len = rand::random::<usize>() % m + 1;
let mut str = String::new();
for _ in 0..len {
let ch = rand::random::<usize>() % r + 'a' as usize;
str.push(ch as u8 as char);
}
ans.push(str);
}
ans
}
fn main() {
const N: usize = 100;
const M: usize = 20;
const R: usize = 5;
const TEST_TIME: usize = 5000;
println!("测试开始");
for _ in 0..TEST_TIME {
let n = rand::random::<usize>() % N + 1;
let strs = random_string_array(n, M, R);
let ans1 = num1(&strs);
let ans2 = num2(&strs);
if ans1 != ans2 {
println!("出错了!");
}
}
println!("测试结束");
}

2023-04-13:给定一个字符串数组strs,其中每个字符串都是小写字母组成的, 如果i < j,并且strs[i]和strs[j]所有的字符随意去排列能组成回文串, 那么说(i,j)叫做一个互补的更多相关文章
- 最长(大)回文串的查找(字符串中找出最长的回文串)PHP实现
首先还是先解释一下什么是回文串:就是从左到右或者从右到左读,都是同样的字符串.比如:上海自来水来自海上,bob等等. 那么什么又是找出最长回文串呢? 例如:字符串abcdefedcfggggggfc, ...
- [LeetCode] Palindrome Partitioning 拆分回文串
Given a string s, partition s such that every substring of the partition is a palindrome. Return all ...
- [LeetCode] Longest Palindromic Substring 最长回文串
Given a string S, find the longest palindromic substring in S. You may assume that the maximum lengt ...
- 回文串--- Girls' research
HDU 3294 Problem Description One day, sailormoon girls are so delighted that they intend to resear ...
- 最长连续回文串(最优线性时间O(n))
转自:http://blog.csdn.net/hopeztm/article/details/7932245 Given a string S, find the longest palindrom ...
- Manacher 算法-----o(n)回文串算法
回文的含义是:正着看和倒着看相同,如abba和yyxyy Manacher算法基本要点:用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插 ...
- UVA 12378 Ball Blasting Game 【Manacher回文串】
Ball Blasting Game Morteza is playing a ball blasting game. In this game there is a chain of differe ...
- 关于回文串的DP问题
问题1:插入/删除字符使得原字符串变成一个回文串且代价最小 poj 3280 Cheapest Palindrome 题意:给出一个由m中字母组成的长度为n的串,给出m种字母添加和删除花费的代价,求让 ...
- HDU 3613 Best Reward(manacher求前、后缀回文串)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3613 题目大意: 题目大意就是将字符串s分成两部分子串,若子串是回文串则需计算价值,否则价值为0,求分 ...
- 计蒜之道 初赛 第三场 题解 Manacher o(n)求最长公共回文串 线段树
腾讯手机地图 腾讯手机地图的定位功能用到了用户手机的多种信号,这当中有的信号的作用范围近.有的信号作用的范围则远一些.有的信号相对于用户在不同的方位强度是不同的,有的则是在不论什么一个方向上信号强度都 ...
随机推荐
- 集群的概念、分类及LVS三种模式总结
1.集群概念: 集群是一组协同工作的服务器,各有分工,对外表现为一个整体. 2.集群分类: 负载均衡集群LBC:分担服务的总体压力 高可用集群HAC:尽可能的保障服务状态的可用性 高性能运算集群HPC ...
- F - Substring of Sorted String
题目链接 题解(树状数组) 我们维护两个树状数组,一个记录 \(1\sim i\) 中 \(s_i>s_{i+1}\)的数量,即逆序对数量,另一个记录 \(1\sim i\) 中 \(26\) ...
- Linux部分文件管理类命令
1.创建空文件和刷新时间 touch命令可以用来创建空文件或刷新文件的时间 touch [OPTION]... FILE... 选项: -a 仅改变atime和ctime -m 仅改变mtime和ct ...
- 如何通过C++ 将数据写入 Excel 工作表
直观的界面.出色的计算功能和图表工具,使Excel成为最流行的个人计算机数据处理软件.在独立的数据包含的信息量太少,而过多的数据又难以理清头绪时,制作成表格是数据管理的最有效手段之一.这样不仅可以方便 ...
- jetbrains账户的注册
注册步骤 1.进入官网界面 官网地址在这里啦:https://www.jetbrains.com/ 官网本来显示的是这个界面: 点击右上角的Learning Tools,然后选择该页面内的这里: 2. ...
- CURL 常用命令
参考博客:https://blog.csdn.net/wangpengfei163/article/details/80900391
- 一遍博客带你上手Servlet
概念 Servlet其实就是Java提供的一门动态web资源开发技术.本质就是一个接口. 快速入门 创建web项目,导入servlet依赖坐标(注意依赖范围scope,是provided,只在编译和测 ...
- img2pdf 报 img2pdf.AlphaChannelError: Refusing to work on images with alpha channel 的解决方案
问题描述: 在使用img2pdf转换png到pdf时候,报了如下错误 img2pdf.AlphaChannelError: Refusing to work on images with alph ...
- 这可能是最全面的Spring面试题总结了
Spring是什么? Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架. Spring的优点 通过控制反转和依赖注入实现松耦合. 支持面向切面的编程,并且把应用业务逻辑和系统 ...
- Centos9网卡配置
Centos9 网卡配置文件已修改,如下 [root@bogon ~]# cat /etc/NetworkManager/system-connections/ens18.nmconnection [ ...