【算法百题之五十九】串联所有单词的子串

                         【算法百题之五十九】串联所有单词的子串

 

   大家好,我是Lampard~~

   很高兴又能和大家见面了,接下来准备系列更新的是算法题,一日一练,早日升仙!

   今天的问题是:串联所有单词的子串

    

示例:

输入:
  s = "barfoothefoobarman",
  words = ["foo","bar"]
输出:[0,9]
解释:
从索引 0 和 9 开始的子串分别是 "barfoo" 和 "foobar" 。
输出的顺序不重要, [9,0] 也是有效答案。

输入:
  s = "wordgoodgoodgoodbestword",
  words = ["word","good","best","word"]
输出:[]

 思路:最直接的思路,判断每个子串是否符合,符合就把下标保存起来,最后返回即可。

然后我们要做的事情就可以分成两个:其一是如何拆分出各个子串,其二是如何判断是否符合。我们先讲第一个,从字符串s中拆分出子串,我们只需要得到words中的字符串拼接起来的目标字符串长度strLength,然后利用string的函数string.strsub(起始位置i,字符串长度strLength)就可以了。第二个问题比较难解决,就是怎么判断出子串是否就是我们想要的

判断是否自己想要的子串:

由于子串包含的单词顺序并不需要固定,如果是两个单词 A,B,我们只需要判断子串是否是 AB 或者 BA 即可。如果是三个单词 A,B,C 也还好,只需要判断子串是否是 ABC,或者 ACB,BAC,BCA,CAB,CBA 就可以了,但如果更多单词呢?那就崩溃了。

用两个 HashMap 来解决。首先,我们把所有的单词存到 HashMap 里,key 直接存单词,value 存单词出现的个数(因为给出的单词可能会有重复的,所以可能是 1 或 2 或者其他)。然后扫描子串的单词,如果当前扫描的单词在之前的 HashMap 中,就把该单词存到新的 HashMap 中,并判断新的 HashMap 中该单词的 value 是不是大于之前的 HashMap 该单词的 value ,如果大了,就代表该子串不是我们要找的,接着判断下一个子串就可以了。如果不大于,那么我们接着判断下一个单词的情况。子串扫描结束,如果子串的全部单词都符合,那么该子串就是我们找的其中一个。

算法代码:

vector<int> findSubstring(string s, vector<string>& words) {
	vector<int> ret;
	if (words.size() == 0) {
		// 判断words为空,因为下面用到了words[0]
		return ret;
	}

	int wordLength = words[0].length();
	int strLength = 0;
	int wordNum = words.size();

	map<string, int> m1;
	for (int i = 0; i < wordNum; i++) {
		// 把每一子串重复出现的次数记录下来
		m1[words[i]]++;
		strLength += words[i].length();
	}

	if (s.length() < strLength) {
		return ret;
	}
	map<string, int> m2;
	string curStr;
	for (int i = 0; i <= s.length() - strLength; i++) {
		curStr = s.substr(i, strLength);
		while (!curStr.empty()) {
			string word = curStr.substr(0, wordLength);
			if (m1.count(word) == 0) {
				break;
			}

			m2[word]++;
			if (m2[word] > m1[word]) {
				break;
			}

			if (curStr.length() == wordLength) {
				curStr = "";
				ret.push_back(i);
			}
			else{
				curStr = curStr.substr(wordLength, strLength);
			}
		}
		m2.clear();
	}
	return ret;
}

要注意一开始输入的就是不合法的情况,考虑程序的健壮性。比如目标字符串比字符串s还长,那就直接返回。

测试结果:

 

OK,今天的博客就到这里,谢谢大家!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lampard杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值