『题目』:
Given a list of words,L, that are all the same length, and a string,S,find the starting position of the substring of S that is a concatenation of each word in L exactly once and without any intervening characters. This substring will occur exactly once in S.
『输入输出』:
输入 | 输出 |
---|---|
L:“mon”,“key” S:“monkey” | 0 |
L:“fooo” “barr” “wing” “ding” “wing” S:“lingmindraboofooowingdingbarrwingmonkeypoundcake” | 13 |
『题意』:
给定一个字符串 S S S,然后给定 n n n 个长度一样的子串,找出在字符串 S S S 中,连串(将这几个子串随便连起来)第一次出现的位置。
『题解』:
我想到的只是最暴力的方法,因为单词长度是固定的,所以也可以用滑动窗口来做,可是因为不知道第一个字符的开头位置,所以只能遍历 S S S 串,所以我这个方法要 O ( l s 2 ) O(l_s^2) O(ls2)的复杂度呢,想法如图所示。
迭代次数 | 包含的字符串 | 第一次出现位置 |
---|---|---|
(左窗口位置,遍历s串位置,右窗口位置) | L:“aaakeymon” S:“mon”,“key” | -1 |
(0,0,0) | aaa不在L串中,left=3 | -1 |
(3,0,3) | key在L串中 | -1 |
(3,0,6) | mon在L串中 | 3 |
『注意』:
该想法没有在OJ上测试过,若有错误请指点
『实现』:
import java.util.HashMap;
import java.util.Scanner;
/**
* Author:
* Gavinjou大笨象
* Date:
* 2019-05-01
* Description:
* 找到连续串联子串
* 暴力滑动窗口
*/
public class faceBook {
//读入的字符串
private static String str;
//要串联的字符串
private static String[] strAarry;
// 存储字符出现的个数
// 因为有可能读入的要匹配字符串有重复的可能
private static HashMap<String,Integer> mapRead;
// 计算当前匹配的字符串串联个数
private static HashMap<String,Integer> mapCount;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
str = sc.nextLine();
//按空格切割字符串
strAarry = str.split(" ");
str = sc.nextLine();
// 左窗口开始位置
int left = 0;
int wordLen = strAarry[0].length();
// 总共要匹配的个数
int sumCount = strAarry.length;
// 连串的总长度
int needLen = wordLen * strAarry.length;
// 答案
int ans = -1;
// 计算匹配个数
int count = 0;
mapRead = new HashMap<>();
//统计字符串
for (int i = 0;i < strAarry.length; i++)
{
if(mapRead.containsKey(strAarry[i]))
{
mapRead.put(strAarry[i],mapRead.get(strAarry[i]) + 1);
}
else
{
mapRead.put(strAarry[i],1);
}
}
for(int i = 0;i <= (str.length() - needLen) && ans == -1;i++)
{
//初始化左窗口
left = i;
mapCount = new HashMap<>();
//移动右窗口
for(int j = left; j <= (str.length() - wordLen) && ans == -1; j += wordLen)
{
//切割S字符串,获取wordLen大小的字符串
String testStr = str.substring(j , j + wordLen);
//如果这个字符串是需要匹配的字符串
if(mapRead.containsKey(testStr))
{
//如果数map包含这个字符串
if(mapCount.containsKey(testStr))
{
//如果需要的个数仍小于要匹配该字符串的个数
if(mapCount.get(testStr) < mapRead.get(testStr))
{
//继续加上去
mapCount.put(testStr,mapCount.get(testStr) + 1);
count++;
}
else
{
mapCount.put(testStr,mapCount.get(testStr) + 1);
//如果个数大于要匹配该字符串的个数
while (mapCount.get(testStr) > mapRead.get(testStr))
{
//找到要匹配的删除的字符串
String rmStr = str.substring(left , left + wordLen);
//统计个数少 1
mapCount.put(rmStr,mapCount.get(rmStr) - 1);
//结果减 1
count -= 1;
left = left + wordLen;
}
}
}
else
{
// 直接加到结果中
mapCount.put(testStr,1);
count++;
}
//如果统计个数已经等于总个数
if(count == sumCount)
{
ans = left;
break;
}
}
else
{
mapCount.clear();
count = 0;
left = j + wordLen;
}
}
}
System.out.println(ans);
}
}