leetcode
leetcode 2351 ~ 2400
最大字符串配对数目

最大字符串配对数目

难度:

标签:

题目描述

You are given a 0-indexed array words consisting of distinct strings.

The string words[i] can be paired with the string words[j] if:

  • The string words[i] is equal to the reversed string of words[j].
  • 0 <= i < j < words.length.

Return the maximum number of pairs that can be formed from the array words.

Note that each string can belong in at most one pair.

 

Example 1:

Input: words = ["cd","ac","dc","ca","zz"]
Output: 2
Explanation: In this example, we can form 2 pair of strings in the following way:
- We pair the 0th string with the 2nd string, as the reversed string of word[0] is "dc" and is equal to words[2].
- We pair the 1st string with the 3rd string, as the reversed string of word[1] is "ca" and is equal to words[3].
It can be proven that 2 is the maximum number of pairs that can be formed.

Example 2:

Input: words = ["ab","ba","cc"]
Output: 1
Explanation: In this example, we can form 1 pair of strings in the following way:
- We pair the 0th string with the 1st string, as the reversed string of words[1] is "ab" and is equal to words[0].
It can be proven that 1 is the maximum number of pairs that can be formed.

Example 3:

Input: words = ["aa","ab"]
Output: 0
Explanation: In this example, we are unable to form any pair of strings.

 

Constraints:

  • 1 <= words.length <= 50
  • words[i].length == 2
  • words consists of distinct strings.
  • words[i] contains only lowercase English letters.

代码结果

运行时间: 16 ms, 内存: 16.3 MB


/*
 * 思路:
 * 1. 使用一个HashSet来保存已访问的字符串。
 * 2. 使用流来处理数组words。
 * 3. 对于每个字符串word,生成它的反转字符串revWord。
 * 4. 检查revWord是否在已访问的字符串集合中,如果在,则匹配成功,增加计数,并从集合中移除revWord。
 * 5. 如果revWord不在集合中,则将当前word添加到集合中。
 * 6. 使用原子整数来保存计数并返回最终结果。
 */
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;

public class Solution {
    public int maximumNumberOfStringPairs(String[] words) {
        HashSet<String> set = new HashSet<>();
        AtomicInteger count = new AtomicInteger(0);
        Stream.of(words).forEach(word -> {
            String revWord = new StringBuilder(word).reverse().toString();
            if (set.contains(revWord)) {
                count.incrementAndGet();
                set.remove(revWord);
            } else {
                set.add(word);
            }
        });
        return count.get();
    }
}

解释

方法:

此题解采用了哈希集合来记录已经遍历过的字符串。对每个字符串,首先检查其反转字符串是否已经存在于集合中,如果存在,则说明找到了一对可以匹配的字符串,因此结果计数加一。如果不存在,则将当前字符串加入到集合中,以便后续字符串进行匹配检查。这种方法利用了集合的高效查找特性,简化了匹配过程。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在此算法中,当发现字符串的反转已存在于集合中时,为什么直接将匹配对数加一而不是将原字符串和反转字符串都从集合中移除?
在算法中,每个字符串只遍历一次,当找到一个匹配(即当前字符串的反转已在集合中)时,说明这对字符串已经形成了一个有效的配对。由于每个字符串只处理一次,将其从集合中移除是不必要的,因为不会再有其他字符串与之配对。此外,移除操作会增加额外的时间复杂度。
🦆
为什么选择使用集合而不是哈希表来存储已遍历的字符串,尽管哈希表可以同时存储字符串及其出现的次数?
在这个特定的算法中,我们只关心字符串是否出现过,而不关心它们出现的次数。使用集合可以提供更快的查找速度和更简洁的代码实现。此外,使用集合可以自动处理重复字符串的情况,因为集合只存储唯一元素。
🦆
在算法实现中,是否考虑了包含相同字符但顺序不同的字符串,例如 'ab' 和 'ba'?这种情况下是否会影响匹配对的计数?
是的,算法考虑了这种情况。如果字符串'ab'和'ba'都出现在输入列表中,当处理到其中一个字符串,比如'ab'时,会将其加入集合。当处理到'ba'时,会发现'ab'的反转即'ba'已经在集合中,从而形成一个匹配对。因此,这种情况正确地被算作一对匹配。
🦆
如果数组中包含自反转字符串(即字符串自身等于其反转,如 'zz'),这种情况在当前算法中是如何处理的?
在当前算法中,自反转字符串在首次遍历到时不会构成匹配对,因为其反转还未出现在集合中。这种字符串只有在出现至少两次时才可能被计为匹配对。例如,如果'zz'在数组中出现两次,第二次遍历到'zz'时,其反转(也是'zz')已经在集合中,这时才会计入一个匹配对。

相关问题