Java描述 LeetCode,438. 找到字符串中所有字母异位词

𝑰’𝒎 𝒉𝒉𝒈, 𝑰 𝒂𝒎 𝒂 𝒈𝒓𝒂𝒅𝒖𝒂𝒕𝒆 𝒔𝒕𝒖𝒅𝒆𝒏𝒕 𝒇𝒓𝒐𝒎 𝑵𝒂𝒏𝒋𝒊𝒏𝒈, 𝑪𝒉𝒊𝒏𝒂.

  • 🏫 𝑺𝒉𝒄𝒐𝒐𝒍: 𝑯𝒐𝒉𝒂𝒊 𝑼𝒏𝒊𝒗𝒆𝒓𝒔𝒊𝒕𝒚
  • 🌱 𝑳𝒆𝒂𝒓𝒏𝒊𝒏𝒈: 𝑰’𝒎 𝒄𝒖𝒓𝒓𝒆𝒏𝒕𝒍𝒚 𝒍𝒆𝒂𝒓𝒏𝒊𝒏𝒈 𝒅𝒆𝒔𝒊𝒈𝒏 𝒑𝒂𝒕𝒕𝒆𝒓𝒏, 𝑳𝒆𝒆𝒕𝒄𝒐𝒅𝒆, 𝒅𝒊𝒔𝒕𝒓𝒊𝒃𝒖𝒕𝒆𝒅 𝒔𝒚𝒔𝒕𝒆𝒎, 𝒎𝒊𝒅𝒅𝒍𝒆𝒘𝒂𝒓𝒆 𝒂𝒏𝒅 𝒔𝒐 𝒐𝒏.
  • 💓 𝑯𝒐𝒘 𝒕𝒐 𝒓𝒆𝒂𝒄𝒉 𝒎𝒆:𝑽𝑿
  • 📚 𝑴𝒚 𝒃𝒍𝒐𝒈: 𝒉𝒕𝒕𝒑𝒔://𝒉𝒉𝒈𝒚𝒚𝒅𝒔.𝒃𝒍𝒐𝒈.𝒄𝒔𝒅𝒏.𝒏𝒆𝒕/
  • 💼 𝑷𝒓𝒐𝒇𝒆𝒔𝒔𝒊𝒐𝒏𝒂𝒍 𝒔𝒌𝒊𝒍𝒍𝒔:𝒎𝒚 𝒅𝒓𝒆𝒂𝒎

1-1: Overview

给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

示例 1:

输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。

示例 2:

输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。

提示:

1 <= s.length, p.length <= 3 * 104
s 和 p 仅包含小写字母
通过次数174,661提交次数321,088

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-all-anagrams-in-a-string
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

1-1: Solution

After completing the analysis of the problem, I thought of the sliding window firstly. There are two windows. One is the fixed-size window. The other is the variable length window. They could also be applied to the solution to this question.

完成问题分析之后,我先想到了滑动窗口,有两种窗口一个是固定大小的,一个是可变长的,两种都可以应用到这道题目。

1-1-1: 定长滑动窗口

Variables

  • counts[]: Record the frequency of each char within the string p or s[left, right]; So, we can judge whether s[left, right] is one arrangement of the string p; Why not use set? Set could only record the existence of the string p. However, the arrangement of string p is not only one. In other words, the chars in p can be arranged in different orders.
  • left: the left boundary of the string to be checked
  • right: the right boundary of the string to be checked

  • counts 是用来记录p/s[left, right] 字符串中每个字符出现的频率,用来判断是否是一个排列。为什么不应set呢?set只能做到是否包含p.做不到是否包含p的一个排列
  • left 左边界
  • right 右边界

Code

public List<Integer> findAnagrams(String s, String p) {
    List<Integer> res = new ArrayList<>();
    int sLength = s.length();
    int pLength = p.length();
    if (pLength > sLength) {
        return res;
    }
    
    //  initial status
    int left = 0;
    int right = pLength - 1;
    int[] sCounts = new int[26];
    int[] pCounts = new int[26];

    for (int i = 0; i < pLength; i++) {
        sCounts[s.charAt(i) - 'a']++;
        pCounts[p.charAt(i) - 'a']++;
    }

    if (Arrays.equals(pCounts, sCounts)) {
        res.add(0);
    }
    
    
    // loop
    while (right < sLength - 1) {
        sCounts[s.charAt(left) - 'a']--;
        left++;
        right++;
        sCounts[s.charAt(right) - 'a']++;
        if (Arrays.equals(pCounts, sCounts)) {
            res.add(left);
        }
    }
    return res;
}

Within interations, change the sacle of the window, judge the string whether it is one arrangement of the pattern.
一次迭代中,改变滑动窗口的范围,判断是不是一个排列。

Complexity Analysis
在这里插入图片描述

1-1-2: 可变长滑动窗口

Code

public List<Integer> findAnagrams2(String s, String p) {
    int[] cnt = new int[26];
    List<Integer> res = new ArrayList<>();

    for (char c : p.toCharArray()) {
        cnt[c-'a']++;
    }


    int low = 0, high = 0;
    while (high < s.length()) {
        char charHigh = s.charAt(high);
        if (cnt[charHigh - 'a'] > 0) {
            cnt[charHigh - 'a']--;
            high++;
            if (high - low == p.length()) {
                res.add(low);
            }
        } else {
            char charLow = s.charAt(low);
            cnt[charLow - 'a']++;
            low++;
        }
    }
    return res;
}

This solution is interesting. The high consume the counts[] and the low add the counts[]. The corner case is that the char charHigh exists within s[left, righ] and not exists within string p; e.g. s[left, high]= “aba”; p = “ab”. cnt[high] = 0. From low to high(including high) counts[low++]++;

这个解决方法比较秒,high用来消费counts数组,low用来补充counts,临界条件就是遇见了不存在p中的字符,比如这里 s[left, high]= “aba”; p = “ab”. 此时cnt[high] = 0,从[low,high] 开始不足counts, 别忘记high 还是指向cnt[high] = 0的,补充完之后,当cnt[high] 由0变成1的时候,就会继续启动high开始消费,从而这个多余的字符就会被跳过去,继续开始新的一轮。关键是处理好那个corner case,临界情况,搞定滑动窗口是如何跳过那个多余的字符的。

Complexity Analysis

  • time:O(n)
  • space: O(1) fixed-size external space could be seen as 1. 固定大小的额外空间可以被当做常数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

河海哥yyds

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

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

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

打赏作者

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

抵扣说明:

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

余额充值