leeCode438_找到字符串中所有字母异位词

一、题目内容

给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的始索引。字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。
说明

  • 字母异位词指字母相同,但排列不同的字符串。
  • 不考虑答案输出的顺序。

示例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" 的字母异位词。

二、题目分析

直接套用之前的模式,使用双指针来模拟一个滑动窗口进行解题。分析过程如下:

假设我们有字符串为“cbaebabacd”,目标串为“abc”
我们通过双指针维护一个窗口,由于我们只需要判断字母异位词,我们可以将窗口初始化大小和目串保持一致。(当然,你也可以初始化窗口为1,逐步扩大)
在这里插入图片描述
而判断字母异位词,我们需要保证窗口中的字母出现次数与目标串中的字母出现次数一致。这里因字母只有26个,直接使用数组来替代map进行存储(和上一讲中的ASCII使用256数组存储思想一致)。

pArr为目标串数组,sArr为窗口数组。我们发现初始化数组,本身就满足,记录下来。(这里图示用map模拟数组,便于理解)
在这里插入图片描述
然后我们通过移动窗口,来更新窗口数组,进而和目标数组匹配,匹配成功进行记录。每一次窗口移动,左指针前移,原来左指针位置处的数值减1,表示字母移出;同时右指针前移,右指针位置处的数值加1,表示字母移入。详细过程如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、代码实现

class Solution { 

	public List<Integer> findAnagrams(String s, String p) { 
		if (s == null || p == null || s.length() < p.length()) 
			return new ArrayList<>(); 
		List<Integer> list = new ArrayList<>(); 

		int[] pArr = new int[26]; 
		int pSize = p.length(); 
		int[] sArr = new int[26];

		for (int i = 0; i < p.length(); i++) { 
			sArr[s.charAt(i) - 'a']++; 
			pArr[p.charAt(i) - 'a']++; 
		}

		for (int i = 0; i < p.length(); i++) { 
			int index = p.charAt(i) - 'a'; 
			if (pArr[index] == sArr[index]) 
				pSize--; 
			}
			int i = 0; 
			int j = p.length(); 
			// 窗口大小固定为p的长度 
			while (j < s.length()) { 
					if (isSame(pArr, sArr)) 
						list.add(i); 
					//sArr[s.charAt(i) - 'a']-- 左指针位置处字母减1 
					sArr[s.charAt(i) - 'a']--; 
					i++;
					//sArr[s.charAt(j) - 'a']++ 右指针位置处字母加1 
					sArr[s.charAt(j) - 'a']++; 
					j++; 
			}
			if (isSame( pArr, sArr)) 
				list.add(i); 
			return list; 
		}
	public boolean isSame(int[] arr1, int[] arr2) { 
		for (int i = 0; i < arr1.length; ++i) 
			if (arr1[i] != arr2[i]) 
				return false;
		return true; 
	} 
}

觉得写得不错的话,请用你们发财的小手点个赞叭!

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Shansec~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值