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)求最长公共回文串 线段树
腾讯手机地图 腾讯手机地图的定位功能用到了用户手机的多种信号,这当中有的信号的作用范围近.有的信号作用的范围则远一些.有的信号相对于用户在不同的方位强度是不同的,有的则是在不论什么一个方向上信号强度都 ...
随机推荐
- Windows软件堆栈溢出(stack overflow)的一些解决方法
欢迎访问我的个人博客:xie-kang.com 原文地址 Windows平台下,有三种方法调整堆栈大小(适用于MSVC编译器): 1)添加编译参数:/F size #其中size的单位是byte可设 ...
- DVWA-Command Injection(命令执行)
命令执行漏洞,顾名思义,服务端在进行一些网站的操作.管理的时候,需要调用系统命令,如果对传入的命令参数没有进行一些过滤,可以直接执行服务器系统的命令终端 LOW 审计源码 <?php // 判断 ...
- Flink模式
Per-job Cluster 该模式下,一个作业一个集群,作业之间相互隔离. 在Per-Job模式下,集群管理器框架用于为每个提交的Job启动一个 Flink 集群.Job完成后,集群将关闭,所有残 ...
- Javaweb学习笔记第十五弹--Listente概述、AJAX、Axiox、JSON
Listener(监听器) 可以在application.session和request三个对象创建 Javaweb提供了8个监听器,其中较为典型的是ServletContextListener监听器 ...
- java.lang.StackOverflowError错误的解决方法
对于java.lang.StackOverflowError认识 如下图所示,报出来这种错误的话,很大概率是有以下几种原因: 现在来看一看我的报错界面: 不难看出,这是无限循环的那种情况,所以,我就去 ...
- Linux & 标准C语言学习 <DAY8_2>
一.函数 Function 一段具有某一项功能的代码集合,是C语言管理代码的最小单位 把代码封装成一个个函数,方便管理和调用函数 1.函数分类 标准库函数: ...
- 车企-TSP系统通用架构设计
最近一年用于参与到了新能源车企的管理系统的开发,并且主要从事架构设计与重难点功能开发的工作,因此有了一些小心得,特此记录(PS:整体和甲方在需求上扯皮,以及协调所有供应商这些项目管理上的事情比做开发耗 ...
- day07-SpringBoot接收参数相关注解
SpringBoot接收参数相关注解 1.基本介绍 SpringBoot接收客户端提交数据/参数会使用到相关注解 详解@PathVariable.@RequestHeader.@ModelAttrib ...
- SQL Server底层架构技术对比
背景 数据库是信息化的基石,支撑着整个业务系统,发挥着非常重要的作用,被喻为"IT的心脏".因此,让数据库安全.稳定.高效地运行已经成为IT管理者必须要面对的问题.数据库在底层架构 ...
- Java GenericObjectPool 对象池化技术--SpringBoot sftp 连接池工具类
Java BasePooledObjectFactory 对象池化技术 通常一个对象创建.销毁非常耗时的时候,我们不会频繁的创建和销毁它,而是考虑复用.复用对象的一种做法就是对象池,将创建好的对象放入 ...