LeetCode 30 Substring with Concatenation of All Words(与所有文字串联子串)(*)

简介:

翻译

给定一个字符串S,一个单词的列表words,全是相同的长度。

找到的子串(多个)以s即每个词的字串联恰好一次并没有任何插入的字符所有的起始索引。

原文

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).

代码

难度对我来说还是太大了,但还是先发个博客占个位置,不然以后顺序就不连串了……

// for sort the |words|
int strcmp1(const void* p1, const void* p2) {
    return strcmp(*(char**)p1, *(char**)p2);
}

// to handle duplicate words in |words|
struct word_t {
    char* w;
    int count;
    int* pos;
    int cur;
};

int word_t_cmp(const void* p1, const void* p2) {
    return strcmp(((const struct word_t*)p1)->w, ((const struct word_t*)p2)->w);
}

/**
 * Return an array of size *returnSize.
 * Note: The returned array must be malloced, assume caller calls free().
 * 
 * It is a variant of the longest-substring-without-repetition problem
 */
int* findSubstring(char* s, char** words, int wordsSize, int* returnSize) {
    if (!s || wordsSize == 0 || strlen(s) < wordsSize*strlen(words[0])) {
        *returnSize = 0;
        return NULL;
    }
    if (strlen(s) == 0 && strlen(words[0]) == 0) {
        *returnSize = 1;
        int* ret = (int*) malloc(sizeof(int));
        ret[0] = 0;
        return ret;
    }

    int n = strlen(s);
    int k = strlen(words[0]);
    // sort |words| first, prepare for binary search
    qsort(words, wordsSize, sizeof(char*), strcmp1);
    // construct array of word_t
    // @note please note that after construction, |wts| is already sorted
    struct word_t* wts = (struct word_t*) malloc(wordsSize * sizeof(struct word_t));
    int wtsSize = 0;
    for (int i = 0; i < wordsSize;) {
        char* w = words[i];
        int count = 1;
        while (++i < wordsSize && !strcmp(w, words[i]))
            count++;
        struct word_t* wt_ptr = wts + wtsSize++;
        wt_ptr->w = w;
        wt_ptr->count = count;
        wt_ptr->pos = (int*) malloc(count * sizeof(int));
        wt_ptr->cur = 0;
    }
    // store one word
    struct word_t wt;
    wt.w = (char*) malloc((k+1) * sizeof(char));
    // return value
    int cap = 10;
    int* ret = (int*) malloc(cap * sizeof(int));
    int size = 0;
    for (int offset = 0; offset < k; offset++) {
        // init word_t array
        for (int i = 0; i < wtsSize; i++) {
            struct word_t* wt_ptr = wts + i;
            for (int j = 0; j < wt_ptr->count; j++)
                wt_ptr->pos[j] = -1;
            wt_ptr->cur = 0;
        }
        int start = offset; // start pos of current substring
        int len = 0; // number of words encountered

        for (int i = offset; i <= n - k; i += k) {
            strncpy(wt.w, s+i, k);
            wt.w[k] = '\0';
            struct word_t* p = (struct word_t*) bsearch(&wt, wts, wtsSize, sizeof(struct word_t), word_t_cmp);
            if (!p) {
                start = i + k;
                len = 0;
                continue;
            }
            // @note the following five lines covers extra occurrence of
            // (possible duplicate) word, you can draw some special case
            // on a paper if it's hard to understand why it could cover
            // all boundary conditions
            // |p->cur| and |p->pos| implement a simple rounded queue,
            // and |p->cur| always point to the smallest index position
            int pos = p->pos[p->cur];
            p->pos[p->cur++] = i;
            if (p->cur >= p->count)
                p->cur -= p->count;
            if (pos < start) { // valid occurrence of this word in current substring started at |start|
                len++;
                if (len == wordsSize) { // all words encounterd, add to result set
                    if (size == cap) { // extend the array
                        cap = 2*cap;
                        int* tmp = (int*) malloc(cap * sizeof(int));
                        memcpy(tmp, ret, size*sizeof(int));
                        free(ret);
                        ret = tmp;
                    }
                    ret[size++] = start;
                    // move substring forward by one word length
                    start += k;
                    len--;
                }
            } else { // extra occurence of (possible duplicat) word encountered, update |start| and |len|
                start = pos + k;
                len = (i - start)/k + 1;
            }
        }
    }

    // cleanup
    for (int i = 0; i < wtsSize; i++)
        free(wts[i].pos);
    free(wts);

    *returnSize = size;
    if (size == 0) {
        free(ret);
        ret = NULL;
    }
    return ret;
}
目录
相关文章
|
10小时前
|
Go
golang力扣leetcode 76.最小覆盖子串
golang力扣leetcode 76.最小覆盖子串
36 0
|
9小时前
|
算法 索引
【刷题】滑动窗口精通 — Leetcode 30. 串联所有单词的子串 | Leetcode 76. 最小覆盖子串
经过这两道题目的书写,相信大家一定深刻认识到了滑动窗口的使用方法!!! 下面请大家继续刷题吧!!!
10 0
|
7月前
|
存储 C语言 C++
【C/C++刷题——leetcode】查找字符串中最大的子串
【C/C++刷题——leetcode】查找字符串中最大的子串
158 0
|
10小时前
|
算法 测试技术 C#
【滑动窗口】【map】LeetCode:76最小覆盖子串
【滑动窗口】【map】LeetCode:76最小覆盖子串
|
10小时前
|
算法 测试技术 C#
【滑动窗口】LeetCode:30串联所有单词的子串
【滑动窗口】LeetCode:30串联所有单词的子串
LeetCode-30 串联所有单词的子串
LeetCode-30 串联所有单词的子串
|
10小时前
|
Java
2696. 删除子串后的字符串最小长度 --力扣 --JAVA
给你一个仅由 大写 英文字符组成的字符串 s 。 你可以对此字符串执行一些操作,在每一步操作中,你可以从 s 中删除 任一个 "AB" 或 "CD" 子字符串。 通过执行操作,删除所有 "AB" 和 "CD" 子串,返回可获得的最终字符串的 最小 可能长度。 注意,删除子串后,重新连接出的字符串可能会产生新的 "AB" 或 "CD" 子串。
20 0
|
5月前
|
Java 测试技术
828. 统计子串中的唯一字符 --力扣 --JAVA
我们定义了一个函数 countUniqueChars(s) 来统计字符串 s 中的唯一字符,并返回唯一字符的个数。
39 2
|
6月前
|
Java
Leetcode 3. Longest Substring Without Repeating Characters
此题题意是找出一个不包含相同字母的最长子串,题目给出了两个例子来说明题意,但这两个例子具有误导性,让你误以为字符串中只有小写字母。还好我是心机boy,我把大写字母的情况也给考虑进去了,不过。。。。字符串里竟然有特殊字符,于是贡献了一次wrong answer,这次我把ascii字符表都考虑进去,然后就没问题了。这个故事告诫我们在编程处理问题的时候一定要注意输入数据的范围,面试中可以和面试官去确认数据范围,也能显得你比较严谨。
29 3
|
9月前
|
算法 C语言 C++
Leetcode 每日一题 1234. 替换子串得到平衡字符串
有一个只含有 'Q', 'W', 'E', 'R' 四种字符,且长度为 n 的字符串
30 0
Leetcode 每日一题 1234. 替换子串得到平衡字符串