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)。

算法过程如下:

  1. 遍历每对字符串(i,j),其中 i<j。
  2. 判断字符串 strs[i] 和 strs[j] 是否可以组成回文串。
  3. 如果可以组成回文串,则互补对数加一。

判断字符串是否可以组成回文串的过程如下:

  1. 统计字符串中每个字符出现的次数。
  2. 如果某个字符出现了奇数次,则不能组成回文串,返回 false。
  3. 如果所有字符都出现了偶数次,或只有一个字符出现了奇数次,则可以组成回文串,返回 true。

算法二

基于状态压缩的哈希表方法,通常也称为“状态压缩 + 哈希表”算法。该算法可以有效地避免枚举所有可能的字符串排列组合,从而实现了较优的时间复杂度。

该算法时间复杂度为 O(N*M),其中,N 表示字符串数组的长度,M 表示单个字符串的平均长度。空间复杂度为 O(N)。其中,空间复杂度主要来自于 status 哈希表的存储。

算法过程如下:

  1. 初始化 hash map status,用于统计每种状态下的字符串数量。
  2. 遍历每个字符串 str。
  3. 计算字符串 str 的状态 cur,即将字符串中每个字符对应的二进制位取反后进行异或操作得到的结果。
  4. 将 status 中 cur 对应的字符串数量加到答案 ans 上。
  5. 遍历每个字符 ch,将 cur 取反后在第 ch 位上的值,即 (cur ^ (1 << ch)),对应的字符串数量加到答案 ans 上。
  6. 将 cur 加入 status 中。

计算状态 cur 的过程如下:

  1. 初始化变量 cur 为 0。
  2. 遍历字符串 str 中的每个字符 ch。
  3. 将 ch 对应的二进制位取反,即 (1 << (ch as usize - ‘a’ as usize))。
  4. 将上一步得到的结果与 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)叫做一个互补的更多相关文章

  1. 最长(大)回文串的查找(字符串中找出最长的回文串)PHP实现

    首先还是先解释一下什么是回文串:就是从左到右或者从右到左读,都是同样的字符串.比如:上海自来水来自海上,bob等等. 那么什么又是找出最长回文串呢? 例如:字符串abcdefedcfggggggfc, ...

  2. [LeetCode] Palindrome Partitioning 拆分回文串

    Given a string s, partition s such that every substring of the partition is a palindrome. Return all ...

  3. [LeetCode] Longest Palindromic Substring 最长回文串

    Given a string S, find the longest palindromic substring in S. You may assume that the maximum lengt ...

  4. 回文串--- Girls' research

    HDU   3294 Problem Description One day, sailormoon girls are so delighted that they intend to resear ...

  5. 最长连续回文串(最优线性时间O(n))

    转自:http://blog.csdn.net/hopeztm/article/details/7932245 Given a string S, find the longest palindrom ...

  6. Manacher 算法-----o(n)回文串算法

    回文的含义是:正着看和倒着看相同,如abba和yyxyy        Manacher算法基本要点:用一个非常巧妙的方式,将所有可能的奇数/偶数长度的回文子串都转换成了奇数长度:在每个字符的两边都插 ...

  7. 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 ...

  8. 关于回文串的DP问题

    问题1:插入/删除字符使得原字符串变成一个回文串且代价最小 poj 3280 Cheapest Palindrome 题意:给出一个由m中字母组成的长度为n的串,给出m种字母添加和删除花费的代价,求让 ...

  9. HDU 3613 Best Reward(manacher求前、后缀回文串)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3613 题目大意: 题目大意就是将字符串s分成两部分子串,若子串是回文串则需计算价值,否则价值为0,求分 ...

  10. 计蒜之道 初赛 第三场 题解 Manacher o(n)求最长公共回文串 线段树

    腾讯手机地图 腾讯手机地图的定位功能用到了用户手机的多种信号,这当中有的信号的作用范围近.有的信号作用的范围则远一些.有的信号相对于用户在不同的方位强度是不同的,有的则是在不论什么一个方向上信号强度都 ...

随机推荐

  1. 微信小程序-实现微信登录

    业务流程: 1:首先需要一个按钮触发事件 2:调用微信小程序的登录接口wx.login,拿到code 3:调用微信小程序的获取用户信息的接口wx.getUserProfile,拿到用户的个人信息 4: ...

  2. VMware安装Rocky Linux8服务器系统并执行优化,包括修改安装镜像源、ssh免密等等

    1. https://blog.csdn.net/DCTANT/article/details/125430461?utm_medium=distribute.pc_relevant.none-tas ...

  3. html、css、js 压缩或混淆方法

    普通的压缩代码的方法包括在线工具和服务器打包处理,有一个共同的痛点是:压缩后的代码无法还原成原始的带有注释的源代码.正如大家所知,在源代码中调试Bug事半功倍.在线工具HCJCompress(ihon ...

  4. VMwareWorkstation-安装虚拟机

    安装vmware 首先就是下载VMware客户端了,Vmware是收费的,过好大多数都有破解版,或者激活码 这里我是用的是VMware16,下载在网上搜一下就有,例如 下载解压后里面有一个后缀为exe ...

  5. Javaweb学习笔记第五弹

    preparedStatement 防止SQL注入:将敏感字符进行转义 1.获取PreparedStatement对象 String sql="selct * from 表名 where 列 ...

  6. DecimalFormat--控制输出格式

    DecimalFormat的相关应用 整数的实现: 小数的实现: 科学计数法: 分组分隔符: 举个例子吧!-- 关于前缀后缀: 本地化货币符号: 引用特殊的字符,作为前缀或者后缀: 实例来袭! 1.0 ...

  7. Linux & 标准C语言学习 <DAY8_2>

    一.函数 Function     一段具有某一项功能的代码集合,是C语言管理代码的最小单位     把代码封装成一个个函数,方便管理和调用函数     1.函数分类         标准库函数:   ...

  8. FastCorrect:语音识别快速纠错模型丨RTC Dev Meetup

    前言 「语音处理」是实时互动领域中非常重要的一个场景,在声网发起的「RTC Dev Meetup丨语音处理在实时互动领域的技术实践和应用」活动中,来自百度.寰宇科技和依图的技术专家,围绕该话题进行了相 ...

  9. 使用golang+antlr4构建一个自己的语言解析器(一)

    Antlr4 简介 ANTLR(全名:ANother Tool for Language Recognition)是基于LL(*)算法实现的语法解析器生成器(parser generator),用Ja ...

  10. 爬取网页的通用代码框架.py(亲测有效)

    import requests def getHTMLText(url): try: kv = {'user-agent':'Mozilla/5.0'} r = requests.get(url,he ...