[LeetCode] 30. Substring with Concatenation of All Words ☆☆☆
You are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s) in s that is a concatenation of each word in words exactly once and without any intervening characters.
For example, given:
s: "barfoothefoobarman"
words: ["foo", "bar"]
You should return the indices: [0,9]
.
(order does not matter).
解法1:
题目要求在给定一个字符串s和一个字符串数组words(有m个字符串,长度均为n)的条件下,找出s中所有“由words中全部字符串按任意顺序串联而成”的子串。
需要用到两个哈希表,第一个存储words数组,key为每一个word,value为出现的次数(考虑到数组中可能会有相同的字符串);第二个哈希表用于存储当前遍历到的子串,value为已出现次数。从s的第一个字符开始遍历,按顺序找到长度为n的子串part,判断part是否在第一个哈希表中,以及当前已出现次数是否超过words数组中的数量,不满足条件的跳出循环并从s的下一个字符继续寻找。
时间复杂度为 O(n2)。
- public class Solution {
- public List<Integer> findSubstring(String s, String[] words) {
- List<Integer> res = new ArrayList<>();
- if (s == null || words == null || words.length == 0) {
- return res;
- }
- HashMap<String, Integer> toFind = new HashMap<>();
- for (String word : words) {
- Integer k = toFind.containsKey(word) ? toFind.get(word) + 1 : 1;
- toFind.put(word, k);
- }
- int m = words.length, n = words[0].length();
- HashMap<String, Integer> found = new HashMap<>();
- for (int i = 0; i <= s.length() - m * n; i++) {
- found.clear();
- int j = i;
- for (; j < i + m * n; j += n) {
- String part = s.substring(j, j + n);
- Integer a = toFind.get(part);
- Integer b = found.get(part);
- if (a == null || (b != null && a <= b)) {
- break;
- }
- found.put(part, b == null ? 1 : ++b);
- }
- if (j == i + m * n) {
- res.add(i);
- }
- }
- return res;
- }
- }
解法2:
仔细研究上面的解法,会发现其中有很多多余的步骤。例如,s="abcdefghijklmn",n=3:第一次遍历从'a'开始,需要遍历"abc", "edf", "ghi"....;而第4次比较从'd'开始,又需要遍历"def", "ghi"....
可以改变上面的思路,从一个字符一个字符遍历,变成一个单词一个单词遍历。将s按照word的长度n进行划分,如s长度为18,m=2,n=3,那么遍历的顺序为:第一次(0,3,6,9,12,15),第二次(1,4,7,10,13,16),第三次(2,5,8,11,14,17)。
首先还是先将words中的单词存到哈希表toFind中。然后从0开始遍历,用left记录当前串联起来的子串的起始位置,curr表示当前的子串(长为n),哈希表found纪录目前串联子串中的每一个word情况。遍历时分以下几种情况:
- curr在toFind中不存在,此时匹配中断,前面从left开始匹配到的都失效。因此,清空found,从下一个子串(curr+n)继续。
- curr在toFind中存在,但在found中不存在,说明前面没有匹配到。因此,将curr记入found中,然后从下一个子串继续。
- curr在toFind和found中都存在,并且found中的数量小于toFind中的数量。将found中的currz数量加一,然后从下一个子串继续。
- curr在toFind和found中都存在,并且两者数量相同,此时再将curr记入found就超过数量限制了。因此,需要从left开始,找到最早出现的同curr相同的子串(设为dupl),并把dupl同之前的子串在found中的纪录删除,然后从left移到dupl的下一个子串,然后curr从curr的下一个子串继续。
每次curr操作结束后,比较当前串联子串的长度是否与与words中所有word长度之和相等,相等则说明当前串联子串匹配成功,将left记入res中,然后从left的下一个子串继续进行。。。。
当 i = 0 遍历完成时,清空found,然后从 i = 1 进行下一次循环。
这个算法实现难度比较大,但是整体的时间复杂度为 O(n)。
- public class Solution {
- public List<Integer> findSubstring(String s, String[] words) {
- List<Integer> res = new ArrayList<>();
- if (s == null || words == null || words.length == 0) {
- return res;
- }
- HashMap<String, Integer> toFind = new HashMap<>();
- for (String word : words) {
- Integer k = toFind.containsKey(word) ? toFind.get(word) + 1 : 1;
- toFind.put(word, k);
- }
- int m = words.length, n = words[0].length();
- HashMap<String, Integer> found = new HashMap<>();
- for (int first = 0; first < n; first++) {
- found.clear();
- int left = first; // 当前串联字符串的起始位置
- for (int curr = first; curr < s.length() && left <= s.length() - m * n; curr += n) {
- String part = s.substring(curr, curr + n);
- if (!toFind.containsKey(part)) { // 如果part不存在,清空found并从下一个位置开始
- found.clear();
- left = curr + n;
- continue;
- }
- if (!found.containsKey(part)) {
- found.put(part, 1);
- } else if (found.get(part) < toFind.get(part)) {
- found.put(part, found.get(part) + 1);
- } else {
- // found和toFind中part数量相同,再添加就超出了,因此需要从left开始,
- // 找到第一个part相同的子串,将其与之前的子串删去,再将其下一个字符串为起点。
- while (!part.equals(s.substring(left, left + n))) {
- Integer x = found.get(s.substring(left, left + n));
- found.put(s.substring(left, left + n), x - 1);
- left += n;
- }
- // 此处需要从found中删除left,再添加curr,但两者相同,故可抵消
- left += n;
- }
- // 如果当前串联子串的长度与数组长度相同,说明成功匹配了一个,
- // 将其记录到res后,从left的下一个子串再继续
- if (curr - left == (m - 1) * n) {
- res.add(left);
- Integer y = found.get(s.substring(left, left + n));
- found.put(s.substring(left, left + n), y - 1);
- left += n;
- }
- }
- }
- return res;
- }
- }
[LeetCode] 30. Substring with Concatenation of All Words ☆☆☆的更多相关文章
- LeetCode - 30. Substring with Concatenation of All Words
30. Substring with Concatenation of All Words Problem's Link --------------------------------------- ...
- [LeetCode] 30. Substring with Concatenation of All Words 解题思路 - Java
You are given a string, s, and a list of words, words, that are all of the same length. Find all sta ...
- leetCode 30.Substring with Concatenation of All Words (words中全部子串相连) 解题思路和方法
Substring with Concatenation of All Words You are given a string, s, and a list of words, words, tha ...
- [LeetCode] 30. Substring with Concatenation of All Words 串联所有单词的子串
You are given a string, s, and a list of words, words, that are all of the same length. Find all sta ...
- Java [leetcode 30]Substring with Concatenation of All Words
题目描述: You are given a string, s, and a list of words, words, that are all of the same length. Find a ...
- [leetcode]30. Substring with Concatenation of All Words由所有单词连成的子串
You are given a string, s, and a list of words, words, that are all of the same length. Find all sta ...
- LeetCode 30 Substring with Concatenation of All Words(确定包含所有子串的起始下标)
题目链接: https://leetcode.com/problems/substring-with-concatenation-of-all-words/?tab=Description 在字符 ...
- [Leetcode][Python]30: Substring with Concatenation of All Words
# -*- coding: utf8 -*-'''__author__ = 'dabay.wang@gmail.com' 30: Substring with Concatenation of All ...
- LeetCode HashTable 30 Substring with Concatenation of All Words
You are given a string, s, and a list of words, words, that are all of the same length. Find all sta ...
随机推荐
- CSS3实现图片渐入效果
很多网站都有那种图片渐入的效果,如:http://www.mi.com/minote/,这种效果用css3和一些js实现起来特别简单. 拿我之前做的页面来说一下怎么利用css3来实现图片渐入效果. 下 ...
- 王者荣耀交流协会--第2次Scrum会议
Scrum master:袁玥 要求1:工作照片 要求2:时间跨度:2017年10月14号 6:02--6:43 共计41min 要求3:地点:一食堂二楼两张桌子旁(靠近卖方便面那边) 要求4:立 ...
- vmvare fusion 8
http://jingyan.baidu.com/article/54b6b9c0f8830f2d583b47ce.html 补充:vmware tools 在上面,直接点击安装
- (工具类)MD5算法|时间格式转换|字符串转数字
package vote.utils; import java.security.MessageDigest; import java.text.SimpleDateFormat; import ja ...
- oracle与DB2的一些架构
首先,我们需要理解 Oracle 使用的架构,并理解它与 DB2 的不同之处.图 1 展示了 Oracle 的系统结构.将该图与 图 2 进行比较,后者显示了 DB2 的系统结构.在阅读本文的时候,为 ...
- Qt多线程-总结QThread-QThreadPool-QtConcurrent
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt多线程-总结QThread-QThreadPool-QtConcurrent 本文 ...
- Viewpoint Meta标签
移动web Viewpoint常用得设置方式: [布局viewpoint] = [设备宽度] = [度量viewpoint] <meta name="viewport" co ...
- 开源人脸识别face_recognition
环境:python36 1.安装dlib.face_recognition windows版 下载dlib,cp后面是py版本 下载地址:https://pypi.org/simple/dlib/ 提 ...
- webgl学习笔记一-绘图单点
写在前面 WebGl(全称:Web Graphics Library : web图形库) 是基于OpenGL ES 2.0的3D绘图协议. WebGL完美地解决了现有的Web交互式三维动画的两 ...
- Git Gerrit Repo User Manual
Git Repo Gerrit User Manual Revision History Revision # Description Date Author ...