哈希表题目:亲密字符串

题目

标题和出处

标题:亲密字符串

出处:859. 亲密字符串

难度

3 级

题目描述

要求

给你两个字符串 s \texttt{s} s goal \texttt{goal} goal,只要我们可以通过交换 s \texttt{s} s 中的两个字母得到与 goal \texttt{goal} goal 相等的结果,就返回 true \texttt{true} true;否则返回 false \texttt{false} false

交换字母的定义是:取两个下标 i \texttt{i} i j \texttt{j} j(下标从 0 \texttt{0} 0 开始)且满足 i ≠ j \texttt{i} \ne \texttt{j} i=j,并交换 s[i] \texttt{s[i]} s[i] s[j] \texttt{s[j]} s[j] 处的字符。

  • 例如,在 "abcd" \texttt{"abcd"} "abcd" 中交换下标 0 \texttt{0} 0 和下标 2 \texttt{2} 2 的元素可以生成 "cbad" \texttt{"cbad"} "cbad"

示例

示例 1:

输入: s   =   "ab",   goal   =   "ba" \texttt{s = "ab", goal = "ba"} s = "ab", goal = "ba"
输出: true \texttt{true} true
解释:你可以交换 s[0]   =   ‘a’ \texttt{s[0] = `a'} s[0] = ‘a’ s[1]   =   ‘b’ \texttt{s[1] = `b'} s[1] = ‘b’ 生成 "ba" \texttt{"ba"} "ba",此时 s \texttt{s} s goal \texttt{goal} goal 相等。

示例 2:

输入: s   =   "ab",   goal   =   "ab" \texttt{s = "ab", goal = "ab"} s = "ab", goal = "ab"
输出: false \texttt{false} false
解释:你只能交换 s[0]   =   ‘a’ \texttt{s[0] = `a'} s[0] = ‘a’ s[1]   =   ‘b’ \texttt{s[1] = `b'} s[1] = ‘b’ 生成 "ba" \texttt{"ba"} "ba",此时 s \texttt{s} s goal \texttt{goal} goal 不相等。

示例 3:

输入: s   =   "aa",   goal   =   "aa" \texttt{s = "aa", goal = "aa"} s = "aa", goal = "aa"
输出: true \texttt{true} true
解释:你可以交换 s[0]   =   ‘a’ \texttt{s[0] = `a'} s[0] = ‘a’ s[1]   =   ‘a’ \texttt{s[1] = `a'} s[1] = ‘a’ 生成 "aa" \texttt{"aa"} "aa",此时 s \texttt{s} s goal \texttt{goal} goal 相等。

示例 4:

输入: s   =   "aaaaaaabc",   goal   =   "aaaaaaacb" \texttt{s = "aaaaaaabc", goal = "aaaaaaacb"} s = "aaaaaaabc", goal = "aaaaaaacb"
输出: true \texttt{true} true

数据范围

  • 1 ≤ s.length,   goal.length ≤ 2 × 10 4 \texttt{1} \le \texttt{s.length, goal.length} \le \texttt{2} \times \texttt{10}^\texttt{4} 1s.length, goal.length2×104
  • s \texttt{s} s goal \texttt{goal} goal 由小写英语字母组成

解法

思路和算法

由于交换字符串中的两个字母不会改变字符串的长度,因此如果可以通过交换 s s s 中的两个字母得到 goal \textit{goal} goal,则一定有 s s s goal \textit{goal} goal 的长度相同。如果 s s s goal \textit{goal} goal 的长度不同,则返回 false \text{false} false

s s s goal \textit{goal} goal 的长度相同时,如果可以通过交换 s s s 中的两个字母得到 goal \textit{goal} goal,则交换的两个字母可能相同或不同。

  • 如果交换的两个字母相同,则 s s s goal \textit{goal} goal 相等且至少有一个字母在同一个字符串中出现超过 1 1 1 次。

  • 如果交换的两个字母不同,则 s s s goal \textit{goal} goal 有两个下标处的字母不同,其余字母相同,假设字母不同的两个下标是 index 1 \textit{index}_1 index1 index 2 \textit{index}_2 index2 index 1 ≠ index 2 \textit{index}_1 \ne \textit{index}_2 index1=index2,则有 s [ index 1 ] = goal [ index 2 ] s[\textit{index}_1] = \textit{goal}[\textit{index}_2] s[index1]=goal[index2] s [ index 2 ] = goal [ index 1 ] s[\textit{index}_2] = \textit{goal}[\textit{index}_1] s[index2]=goal[index1]

根据上述分析,可以同时遍历 s s s goal \textit{goal} goal,判断是否可以通过交换 s s s 中的两个字母得到 goal \textit{goal} goal。遍历过程中需要记录每个字母的出现次数、是否有重复字母、字母不同的下标个数和字母不同的下标。对于每个下标 i i i,进行如下操作:

  1. s [ i ] s[i] s[i] 的出现次数加 1 1 1,如果该字母的出现次数大于 1 1 1,则有重复字母;

  2. 如果 s [ i ] ≠ goal [ i ] s[i] \ne \textit{goal}[i] s[i]=goal[i],则将字母不同的下标个数加 1 1 1,并更新字母不同的下标,如果字母不同的下标个数大于 2 2 2,则返回 false \text{false} false

遍历结束之后,字母不同的下标个数一定不会大于 2 2 2(否则在遍历过程中就返回 false \text{false} false)。根据字母不同的下标个数,结果分别如下:

  • 如果字母不同的下标个数是 1 1 1,则返回 false \text{false} false

  • 如果字母不同的下标个数是 0 0 0,则当有重复字母时返回 true \text{true} true,否则返回 false \text{false} false

  • 如果字母不同的下标个数是 2 2 2,则当 s [ index 1 ] = goal [ index 2 ] s[\textit{index}_1] = \textit{goal}[\textit{index}_2] s[index1]=goal[index2] s [ index 2 ] = goal [ index 1 ] s[\textit{index}_2] = \textit{goal}[\textit{index}_1] s[index2]=goal[index1] 都成立时返回 true \text{true} true,否则返回 false \text{false} false

代码

class Solution {
    public boolean buddyStrings(String s, String goal) {
        if (s.length() != goal.length()) {
            return false;
        }
        int[] counts = new int[26];
        boolean repeat = false;
        int length = s.length();
        int different = 0, index1 = -1, index2 = -1;
        for (int i = 0; i < length; i++) {
            char c1 = s.charAt(i), c2 = goal.charAt(i);
            counts[c1 - 'a']++;
            if (counts[c1 - 'a'] > 1) {
                repeat = true;
            }
            if (c1 != c2) {
                different++;
                if (different == 1) {
                    index1 = i;
                } else if (different == 2) {
                    index2 = i;
                } else {
                    return false;
                }
            }
        }
        if (different == 1) {
            return false;
        }
        if (different == 0) {
            return repeat;
        } else {
            return s.charAt(index1) == goal.charAt(index2) && s.charAt(index2) == goal.charAt(index1);
        }
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 s s s goal \textit{goal} goal 的长度。需要遍历两个字符串各一次,遍历过程中维护相关信息,遍历结束之后判断的时间是 O ( 1 ) O(1) O(1)

  • 空间复杂度: O ( ∣ Σ ∣ ) O(|\Sigma|) O(∣Σ∣),其中 Σ \Sigma Σ 是字符集,这道题中 Σ \Sigma Σ 是全部小写英语字母, ∣ Σ ∣ = 26 |\Sigma| = 26 ∣Σ∣=26。空间复杂度主要取决于哈希表,需要使用哈希表记录每个字母的出现次数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值