『面试题』找连续子串

『题目』:

 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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值