leetcode 30

题意:给定一个字符串s和一个字符串数组words,找出s中所有以words中全部字符串拼接成的字符串作为子串的起始索引并返回。

For example, given:
s: “barfoothefoobarman”
words: [“foo”, “bar”]
You should return the indices: [0,9].
(order does not matter).

注意:words中的元素是有可能重复的。

思路:令 len = words[0].length;
满足题意的子串是words中的各元素以任意顺序组合而成,引入滑动窗口的概念,滑动窗口从左至右遍历s,每次“读入”一个单词,最后滑动窗口包含的子串就是满足题意的子串。

(1)使用Map 1把words中出现的字符串和次数记录下来。
(2)滑动窗口初始大小为0,每次读入一个len长度的字符串,另外使用一个Map 2维护窗口中的字符串和出现的次数。
(3)窗口每次读入一个len长度字符串后,需要判断这个字符串是否是words中出现的(利用第(1)步中的Map 1),如果Map 1中不包含这个字符串,则窗口需要初始化为0,转到第(2)步,重新读入下一个字符串;如果Map 1中包含这个字符串,则把这个字符串记录到Map 2中,转到第(4)步。
(4)判断这个字符串出现的次数是否大于在Map 1中保存的次数,如果大于,则窗口需要从左侧收缩,直到次数等于Map 1中的次数;如果不大于,转到第(5)步。
(5)判断窗口的宽度是否等于len * words.length,如果等于,表明此窗口是满足题意的,返回初始索引;如果不等于,继续读入,直到等于。继续构造下一个窗口。

下图为一个示意图,假设words中有3个元素。

这里写图片描述

叙述真的很难,贴上代码吧

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Test {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String[] words = {"foo", "bar",};
        String s = "barfoothefoobarman";
        List<Integer> list = findSubstring(s, words);
        for (int i : list)
            System.out.print(i + " ");
    }


    public static List<Integer> findSubstring(String s, String[] words){
        int lenOfWord = words[0].length();
        int len = words.length;
        List<Integer> list = new ArrayList<>();
        Map<String, Integer> map = new HashMap<>();
        for (String a : words) {
            map.put(a, map.containsKey(a) ? map.get(a) + 1 : 1);
        }
        for (int i = 0; i < lenOfWord; i++) {
            Map<String, Integer> window = new HashMap<>();
            int left = i, right = i;
            while (right <= s.length() - lenOfWord) {
                String word = s.substring(right, right + lenOfWord);
                right += lenOfWord;
                if (map.containsKey(word)) {
                    window.put(word, window.containsKey(word) ? window.get(word) + 1 : 1);
                    while (window.get(word) > map.get(word)) {
                        String head = s.substring(left, left + lenOfWord);
                        left += lenOfWord;
                        window.put(head, window.get(head) - 1);
                    }
                } else {
                    window.clear();
                    left = right;
                }
                if (right - left == len * lenOfWord) {
                    list.add(left);
                    window.clear();
                    left += lenOfWord;
                    right = left;
                }
            }
        }
        return list;
    }
}

稍微解释一下为什么外层循环只需要 i 从 0 到 lenOfWord - 1吧,因为当 i 变为 lenOfWord 之后,情形就和 i 为 0 时一样了。

后续再改这篇文章吧,感觉一时半会儿也讲不清,后面会尽量多贴图说明的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值