原题链接:https://leetcode.com/problems/substring-with-concatenation-of-all-words/
题目: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 wordsexactly 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).
题目意思:就是在s中找到所有的序号,从这些序号开始的所有的单词,全都包含了words中的单词,并且中间不能含有其它的单词。
解题思路:
(1)首先应该建一个hashmap,以words的单词作为map的key,以words中出现的数量作为value值。
(2)在s中进行遍历,因为每个words中的单词长度都是固定的length,所以依次比较(i,i+length-1),(i+length,i+2*length-1),(i+2*length, i+3*length-1)。。。看是否能和words中的单词都能进行匹配。
(3)若可以匹配,则保存i,继续判断s中的i+1作为起始位置。。。依次类推
代码实现:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SIZE 1000
typedef struct Node{
char *word;
int times;
struct Node *next;
}data;
int hash(char *word){
int i = 0, h = 0;
for(i=0; word[i]; i++) {
h = (h*31+word[i])%SIZE;
}
return h;
}
//根据words构建字典
int insertMap(data **map, char *word, int length) {
int h = hash(word);
if (map[h] == NULL) {
map[h] = (data *) malloc (sizeof(data));
map[h]->word = (char *) malloc (sizeof(char) * (length+1));
strcpy(map[h]->word, word);
map[h]->times = 1;
map[h]->next = NULL;
return 1;
} else {
data *p = map[h];
while (p->next != NULL) {
if (strcmp(p->word, word) == 0) {
p->times++;
return p->times;
}
p = p->next;
}
if (strcmp(p->word, word) == 0) {
p->times++;
return p->times;
} else {
data *tmp = (data *) malloc (sizeof(data));
tmp->word = (char *) malloc (sizeof(char) * (length+1));
strcpy(tmp->word, word);
tmp->times = 1;
p->next = tmp;
tmp->next = NULL;
return 1;
}
}
}
//查询字典,并返回此单词的数目
int findMap(data **map, char *sub) {
int h = hash(sub);
if (map[h] == NULL) {
return -1;
} else {
data *p = map[h];
while (p != NULL) {
if (strcmp(p->word, sub) == 0) {
return p->times;
}
p = p->next;
}
return -1;
}
}
char *substring(char *s, int start, int len) {
char *sub = (char *) malloc (sizeof(char) * (len+1));
int i=0;
for (; i < len; i++) {
sub[i] = s[i+start];
}
sub[i] = '\0';
return sub;
}
/**
* Return an array of size *returnSize.
* Note: The returned array must be malloced, assume caller calls free().
*/
int* findSubstring(char* s, char** words, int wordsSize, int* returnSize) {
*returnSize = 0;
if (s == NULL || words == NULL) {
return NULL;
}
int sLen = strlen(s), wLen = strlen(words[0]);
int *result = (int *) malloc (sizeof(int) * (sLen-wLen*wordsSize+1));
data **map = (data **) malloc (sizeof(data *) * SIZE);
data **tmp = (data **) malloc (sizeof(data *) * SIZE);
int i, j;
for (i = 0; i < SIZE; i++) {
map[i] = NULL;
tmp[i] = NULL;
}
//构建字典
for (i = 0; i < wordsSize; i++) {
insertMap(map, words[i], wLen);
}
for (i = 0; i <= sLen-wLen*wordsSize; i++) {
for (j = 0; j < SIZE; j++) {
if (tmp[j] != NULL) {
free(tmp[j]);
tmp[j] = NULL;
}
}
for (j = 0; j < wordsSize; j++) {
char *sub = substring(s, i+j*wLen, wLen);
int mapnum = findMap(map, sub);
if (mapnum == -1) break;
int num = insertMap(tmp, sub, wLen);
if (num > mapnum) break;
free(sub);
}
if (j >= wordsSize) {
result[(*returnSize)++] = i;
}
}
for (i = 0; i < SIZE; i++) {
if (map[i] != NULL) {
free(map[i]);
}
}
free(map);
return result;
}
以上代码参考了别人的一篇博客。
还有一种方法是滑动窗口的方法,思路仍然是维护一个窗口,如果当前单词在字典中,则继续移动窗口右端,否则窗口左端可以跳到字符串下一个单词了:http://blog.csdn.net/linhuanmars/article/details/20342851