查找给定字符串数组全组合的子串


/*
给定一个字符串 s 和一个字符串数组 words。 words 中所有字符串 长度相同。

 s 中的 串联子串 是指一个包含  words 中所有字符串以任意顺序排列连接起来的子串。

例如,如果 words = ["ab","cd","ef"], 那么 "abcdef", "abefcd","cdabef", "cdefab","efabcd", 和 "efcdab" 都是串联子串。 "acdbef" 不是串联子串,因为他不是任何 words 排列的连接。
返回所有串联字串在 s 中的开始索引。你可以以 任意顺序 返回答案。

 

示例 1:

输入:s = "barfoothefoobarman", words = ["foo","bar"]
输出:[0,9]
解释:因为 words.length == 2 同时 words[i].length == 3,连接的子字符串的长度必须为 6。
子串 "barfoo" 开始位置是 0。它是 words 中以 ["bar","foo"] 顺序排列的连接。
子串 "foobar" 开始位置是 9。它是 words 中以 ["foo","bar"] 顺序排列的连接。
输出顺序无关紧要。返回 [9,0] 也是可以的。
示例 2:

输入:s = "wordgoodgoodgoodbestword", words = ["word","good","best","word"]
输出:[]
解释:因为 words.length == 4 并且 words[i].length == 4,所以串联子串的长度必须为 16。
s 中没有子串长度为 16 并且等于 words 的任何顺序排列的连接。
所以我们返回一个空数组。
示例 3:

输入:s = "barfoofoobarthefoobarman", words = ["bar","foo","the"]
输出:[6,9,12]
解释:因为 words.length == 3 并且 words[i].length == 3,所以串联子串的长度必须为 9。
子串 "foobarthe" 开始位置是 6。它是 words 中以 ["foo","bar","the"] 顺序排列的连接。
子串 "barthefoo" 开始位置是 9。它是 words 中以 ["bar","the","foo"] 顺序排列的连接。
子串 "thefoobar" 开始位置是 12。它是 words 中以 ["the","foo","bar"] 顺序排列的连接。
 

提示:

1 <= s.length <= 10^4
1 <= words.length <= 5000
1 <= words[i].length <= 30
words[i] 和 s 由小写英文字母组成

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/substring-with-concatenation-of-all-words
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#define MAX_LEN 32

struct words_info {
    char word[MAX_LEN];
    short int times;
};

//use bisect insert to make it an order array, if same string, times++
static int sort_words_info(struct words_info words_inf[], const char **words, int words_size, int one_len)
{
    int i, j, count = 0;

    //strcpy(words_inf[0].word, words[0]);
    //words_inf[0].times = 1;

    for (i = 0; i < words_size; i++) {

        int right = 0, left = count - 1;
        while (right <= left) {

            int index = right + (left - right) / 2;
            int ret = strncmp(words[i], words_inf[index].word, one_len);

            if (ret > 0) {
                right = index + 1;
            } else if (ret < 0) {
                left = index - 1;
            } else {
                words_inf[index].times++; //if match in the pre-array, just ++1
                break;
            }
        }
    
        //matched in pre-array
        if (right <= left) {
            continue;
        }

        //move one step forward
        for (j = count; j > right; j--) {
            memcpy(&words_inf[j], &words_inf[j-1], sizeof(struct words_info));
        }
    
        strncpy(words_inf[right].word, words[i], one_len);
        words_inf[right].times = 1;    
        count++;
    }

    return count;
}

//also use bisect search to find the index to match the word
static short int match_word(const char *word, int one_len, struct words_info words_inf[], int words_count)
{
    int right = 0, left = words_count - 1;
    short int match_index = -1;

    while (right <= left) {

        int index = right + (left - right) / 2;
        int ret = strncmp(word, words_inf[index].word, one_len);

        if (ret > 0) {
            right = index + 1;
        } else if (ret < 0) {
            left = index - 1;
        } else {
            match_index = index;
            break;
        }
    }

    return match_index;
}

static bool check_match(short match_times[], short matchs[], int from, int check_count, int total_len, int one_len,
                struct words_info words_inf[], int words_count)
{
    int i, j;
    bool ret = false;

    //calc all words match times
    for (i = 0, j = from; (i < check_count) && (j < total_len); i++, j+=one_len) {
        if (matchs[j] != -1) {
            match_times[matchs[j]]++;
        } else {
            break;
        }
    }

    if (i != check_count) {
        return ret;
    }

    //i == check_count: all check_count has valid matched value, then check matched all words info
    for (i = 0; i < words_count; i++) {
        if (match_times[i] != words_inf[i].times) {
            break;
        }
    }

    if (i == words_count) {
        ret = true;
    }

    return ret;
}

/**
 * Note: The returned array must be malloced, assume caller calls free().
 */
int* findSubstring(char * s, char ** words, int wordsSize, int* returnSize)
{
    int total_len = strlen(s);
    int one_len = strlen(words[0]);
    int i = 0, j = 0;

    *returnSize = 0;
    if (total_len < (one_len * wordsSize)){
        return NULL;
    }

    struct words_info *words_inf = (struct words_info *)malloc(sizeof(struct words_info) * wordsSize);
    int words_count = sort_words_info(words_inf,(const char **)words, wordsSize, one_len);

    short int *matchs = (short int *)malloc(sizeof(short int) * total_len);

    for (i = 0; i < total_len; i++) {
        matchs[i] = match_word(s + i, one_len, words_inf, words_count);
    }

    short int *match_times = (short int *)malloc(sizeof(short int) * words_count);
    int *match_pos = (int *)malloc(sizeof(int) * total_len);

    for (i = 0; i < total_len; i++) {
        memset(match_times, 0, sizeof(short int) * words_count);
        if (check_match(match_times, matchs, i, wordsSize, total_len, one_len, words_inf, words_count)) {
            match_pos[j++] = i;
        }
    }

    free(match_times);
    free(matchs);
    free(words_inf);

    if (j == 0) {
        free(match_pos);
        return NULL;
    }

    *returnSize = j;
    return match_pos;
}

int main(int argc, char *argv[])
{
    char *s = "wordgoodgoodgoodbestword";
    char *words[] = {"word", "good", "best", "word"};

//    char *s = "barfoofoobarthefoobarman";
//    char *words[] = {"bar", "foo", "the"};

    int size = 0;
    int *ret = findSubstring(s, words, 4, &size);

    printf("[");
    for (int i = 0; i < size; i++) {
        printf("%d ", ret[i]);
    }
    printf("]\n");
    free(ret);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值