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)求最长公共回文串 线段树
腾讯手机地图 腾讯手机地图的定位功能用到了用户手机的多种信号,这当中有的信号的作用范围近.有的信号作用的范围则远一些.有的信号相对于用户在不同的方位强度是不同的,有的则是在不论什么一个方向上信号强度都 ...
随机推荐
- 禅道 docker 部署
官方文档:https://hub.docker.com/r/idoop/zentao 1.创建本地目录:mkdir -p /data/zbox 2.启动容器: sudo docker run -itd ...
- egret 当前运行环境
if(egret.Capabilities.runtimeType == egret.RuntimeType.WXGAME){}
- vue项目 运行内存溢出
运行vue项目报错,内存溢出!!! <--- Last few GCs ---> [10400:00000218A86135D0] 173902 ms: Mark-sweep (reduc ...
- luffy项目settings
一: 二:. 设置调整 1.修改manage.py配置路径 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffyApi.settings.de ...
- 网络如何运作——详细DNS、HTTP、网站
详细的DNS 什么是DNS? DNS(域名系统)为我们提供了一种简单的方式来与互联网上的设备进行通信,而无需记住复杂的数字.就像每个房子都有一个唯一的地址可以直接向它发送邮件一样,互联网上的每台计算机 ...
- Web For Pentester File include
File include(文件包含) Example 1 没有任何过滤 审计源码 没有对我们传参的page进行任何过滤,payload如下 http://172.16.1.104/fileincl/e ...
- Javaweb基础知识复习------AJAX
AJAX相关知识复习 简而言之,就是可以用AJAX+HTML代替JSP页面,也可以进行异步交互,更新部分界面 Ajax案例 后端代码就是一个servlet文件,前端页面的代码也不是很常用,可以在下面这 ...
- 【读书笔记】排列研究-模式避免-续篇Pattern Avoidance
目录 多项式递归Polynomial Recursions P-recursive和c-recursive定义 例子:卡特兰数序列是P-recursive(或者说D-finite) 两个说明\(S_n ...
- Java中的String类真的不可变吗?java面试常见问题
其实在Java中,String类被final修饰,主要是为了保证字符串的不可变性,进而保证了它的安全性.那么final到底是怎么保证字符串安全性的呢?接下来就让我们一起来看看吧. 一. final ...
- Java (强/弱/软/虚)引用
一.整体架构