LeetCode --- 字符串系列 --- 特殊等价字符串组
特殊等价字符串组
注释:这道题目题意太过难理解,理解题意花了几小时... 下面将对题目进行括号注释....
题目
你将得到一个字符串数组 A。比如 (
["a2cd","ac2d","2acd", "c2ad"]
)
如果经过任意次数的移动,S == T,那么两个字符串 S 和 T 是特殊等价的。
(比如上面给出的字符串数组,若其中两个数组元素字符串,自身的字符发生任意次数的移动,
移动次数不用相等,最后这两个字符串可以相等,那么就说这两个字符串是等价的。
在这个字符串数组中,可以存在多个等价字符串)
一次移动包括选择两个索引 i 和 j,且 i % 2 == j % 2,交换 S[j] 和 S [i]。
(这里意思是上面所说到的任意次移动,每次移动,需要移动字符串中的两位,这两位互相交换位置;
移动的这两位位置要满足条件 i % 2 == j % 2。即 i 和 j 都是偶数或者奇数。
换个说法,对字符串进行奇数位交换操作,或者偶尔位交换操作或者奇数位交换完成后,进行偶数位交换,次数不限)
拿上面的例子:
每个数组字符串元素各经过一次(实际可以交换多次)偶数位和奇数位交换:
`a2cd` 偶数变化-> adc2 -> 偶数位再变一次(变回来了) `a2cd`
奇数变化-> `c2ad`
ac2d 偶数变化-> 2cad
奇数变化-> ad2c
2acd 偶数变化-> ca2d
奇数变化-> 2dca
`c2ad` 偶数变化-> `a2cd`
奇数变化-> cda2`
观察发现 a2cd
和 c2ad
经过上面的变化之后可以相等,那么这两个就是等价的
且
原字符串
经过任意次数变化可以变回自己,所以每个字符串跟自己是特殊等价
的
现在规定,A 中的特殊等价字符串组是 A 的非空子集 S
这样不在 S 中的任何字符串与 S 中的任何字符串都不是特殊等价的。
(这里加了一个限制条件:不在 S 中的任何字符串与 S 中的任何字符串都不是特殊等价的
应该为不在 S 中任何的字符串(即在 A 中刨去 S 字符串之后的剩下字符串)与 S 中的任何字符串都不是特殊等价的
)
(上面我说,每个字符串跟自己是特殊等价的, 单个字符串
如果没有其他字符串和他自己等价,那么他自己就组成了一个等价字符串数组,保证了 S 是 A 的非空子集。
但是也可以这么想,是不是因为有了这条规定:A 中的特殊等价字符串组是 A 的非空子集 S
,才限制我们若 单个字符串
没有其他字符串和他自己等价,他自己就组成了一个等价字符串数组)
返回 A 中特殊等价字符串组的数量。
示例
示例 1:
输入:["a","b","c","a","c","c"]
输出:3
解释:3 组 ["a","a"],["b"],["c","c","c"]
示例 2:
输入:["aa","bb","ab","ba"]
输出:4
解释:4 组 ["aa"],["bb"],["ab"],["ba"]
示例 3:
输入:["abc","acb","bac","bca","cab","cba"]
输出:3
解释:3 组 ["abc","cba"],["acb","bca"],["bac","cab"]
示例 4:
输入:["abcd","cdab","adcb","cbad"]
输出:1
解释:1 组 ["abcd","cdab","adcb","cbad"]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/groups-of-special-equivalent-strings/
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
1、字符串数组中的元素可以进行任意次偶数、奇数位移动,产生多个排列组合
若有另外一个字符串也经过这样的操作产生排列组合,这两个排列组合中有相等的一对,那么这两个 `原字符串` 就是特殊等价的
2、所以第一步对字符串进行排列
3、第二步找出两个排列组合中相等的一对
或者
较好力扣题解
1、
字符串切割,过滤奇数位字符串,排序拼接
加上
字符串切割,过滤偶数位字符串,排序拼接
2、若是等价字符,则经过此操作将会相等
3、最后利用 Set 的去重特性,转换成数组,可以得到最终长度
题解
let numSpecialEquivGroups = function (A) {
let obj = {}
// 遍历字符串数组
for (let i = 0; i < A.length; i++) {
// 匹配计数,偶数字符串,奇数字符串
let count = 0, evens = '', odds = ''
A[i].replace(/\w/g, w => {
count++
// 匹配到字符 count 就加 1
// 分别收集偶数位和奇数位的字符串
if (count % 2 === 0) {
evens += w
} else {
odds += w
}
})
// 排序
evens = evens.split('').sort()
odds = odds.split('').sort()
let key = ''
// 以奇数字符串开始,顺序插入偶数位
odds.forEach((w, index) => {
key += w + (evens[index] ? evens[index] : '')
})
// 将排列后相同的原字符串归类收集起来
obj[key] = obj[key] || []
obj[key].push(A[i])
}
// 最后返回 obj 的属性长度
return Object.keys(obj).length
}
或者
较好力扣题解
const numSpecialEquivGroups = (A) =>
[
...new Set(
A.map(
(item) =>
// 字符串切割,过滤奇数位字符串,排序拼接
// 加上
// 字符串切割,过滤偶数位字符串,排序拼接
// 若是等价字符,则经过此操作将会相等
// 最后利用 Set 的去重特性,转换成数组,可以得到最终长度
item
.split('')
.filter((t, i) => i % 2 === 1)
.sort()
.join('') +
item
.split('')
.filter((t, i) => i % 2 === 0)
.sort()
.join('')
)
),
].length