LeetCode-Substring with Concatenation of All Words

题目链接:

https://leetcode.com/problems/substring-with-concatenation-of-all-words/

参考链接:

http://www.w2bc.com/Article/14500


思路:

题目大意为,给定一个字符串S和一个字符串数组L,L中的各字符串长度均相等。找出S中所有的子串,这些子串恰好包含L中所有字符各一次,返回子串启始位置。

解题步骤:

1.用map表示L,map中的Key为L中的各字符串,Value为该字符串出现次数

2.执行循环,用str表示S中的各字符串,cnt表示S中包含的L中字符串的个数。若map中key包含str且对应的value大于0(因为要恰好包含1次,),则cnt++,map中str对应的value--。若cnt==
L.length,则这一段满足题目要求。接着再次初始化map,继续执行循环

3.返回结果集


code:

package alivebao;

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

/**
 * You are given a string, S, and a list of words, L, that are all of the same
 * length. Find all starting indices of substring(s) in S that is a
 * concatenation of each word in L exactly once and without any intervening
 * characters.
 * 
 * For example, given: S: "barfoothefoobarman" L: ["foo", "bar"]
 * 
 * You should return the indices: [0,9]. (order does not matter).
 * 
 * @author Administrator
 * 
 */
public class Solution {
	public static List<Integer> findSubstring(String S, String[] L) {
		List<Integer> ans = new ArrayList<Integer>();
		if (S.length() < 1 || L.length < 1)
			return ans;
		int len = L[0].length(); // 题目说L中每个单词长度一样

		// 初始化HashMap,注意L中可能包含多个相同的字符串,所以用value表示个数
		HashMap<String, Integer> map = new HashMap<String, Integer>();
		for (int j = 0; j < L.length; j++) {
			if (map.containsKey(L[j])) {
				map.put(L[j], map.get(L[j]) + 1);
			} else {
				map.put(L[j], 1);
			}
		}

		// i的范围很关键,如果直接到S.length()是会超时的
		for (int i = 0; i <= S.length() - L.length * len; i++) {
			int from = i;
			String str = S.substring(from, from + len);
			int cnt = 0;
			while (map.containsKey(str) && map.get(str) > 0) {
				map.put(str, map.get(str) - 1);
				cnt++;
				from += len;
				if (from + len > S.length())
					break; // 注意越界
				str = S.substring(from, from + len);
			}

			// L中每个单词恰好出现一次,加入到结果集
			if (cnt == L.length) {
				ans.add(i);
			}

			// 为下一次初始化HashMap
			if (cnt > 0) {
				map.clear();
				for (int j = 0; j < L.length; j++) {
					if (map.containsKey(L[j])) {
						map.put(L[j], map.get(L[j]) + 1);
					} else {
						map.put(L[j], 1);
					}
				}
			}
		}

		return ans;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String s = "barfoothefoobarman";
		String[] L = { "foo", "bar" };
		List<Integer> a = new ArrayList<Integer>();
		a = findSubstring(s, L);
		for (Integer t : a) {
			System.out.println(t);
		}
	}

}

PS:感觉还有一种解法,类似Leetcode里的 Longest Substring Without Repeating Characterse,大概思路为先用移动窗口的办法求出字符串S中各不重复的子串,然后判断各子串中是否含有L


Longest Substring Without Repeating Characters的大致要求即为求出最长的不重复子串。解法:

Longest Substring Without Repeating Characters

package alivebao;


/**
 * Given a string, find the length of the longest substring without repeating
 * characters. For example, the longest substring without repeating letters for
 * "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring
 * is "b", with the length of 1.
 * 
 * @author Administrator
 * 
 */
public class Solution {

	public static int lengthOfLongestSubstring(String s) {
		int maxLen = 0;
		if (s == null || s.length() == 0)
			return 0;
		HashSet<Character> set = new HashSet<Character>();
		int walker = 0;
		int runner = 0;
		while (runner < s.length()) {
			if (set.contains(s.charAt(runner))) {
				if (maxLen < runner - walker)
					maxLen = runner - walker;
				while (s.charAt(walker) != s.charAt(runner)) {
					set.remove(s.charAt(walker));
					walker++;
				}
				walker++;
			} else
				set.add(s.charAt(runner));
			++runner;
		}
		maxLen = Math.max(maxLen, runner - walker);
		return maxLen;
	}

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		System.out.println(lengthOfLongestSubstring("ababc"));
	}

}

解决思路:

用两个下标walker和runner组成一个不包含重复字符的窗口,runner每次向右移一个字符,若该字符与窗口中的各字符不重复,则继续右移。若重复,则walker移至与runner位置指向的字符相同的字符位置之后一位(比如说walker与runner组成的窗口中第三个字符与runner此时指向的字符相同,则将walker移动至窗口的第四个字符的位置),建立一个新窗口,继续循环


把这题的思路应用于本题,可求出字符串S中,以L[0].length为单位的各不重复子串,然后判断是否包含L。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值