Post

1408. String Matching in an Array

1408. String Matching in an Array

[Problem]

Easy

Array String String Matching


Intuition

  • This can be achieved using either a brute force approach or the more efficient KMP algorithm for substring matching.

  • Although brute force will work in the question as the constraints are small, we would discuss both the approaches here.

    1
    2
    3
    
      Constraints:
      1 <= words.length <= 100
      1 <= words[i].length <= 30
    

Resources

Before attempting this problem, consider reviewing MY TAKE ON THE KMP ALGORITHM for a clear explanation of the KMP algorithm approach.

Approach 1: Brute Force

  • Compare each string with all other strings in the array.
  • Check if one string is a substring of another using Java’s .contains() method.
  • Add the substring to the result list if not already present.

Complexity Analysis

  • Time Complexity: O(n^2 * m)
    • n: Number of strings in the array.
    • m: Average length of the strings.
  • Space Complexity: O(k)
    • k: Space used to store the result list.

Approach 2: KMP Algorithm

  • For each string, check if it is a substring of another string using the precomputed LPS (Longest Prefix Suffix) array.
  • Avoid duplicates by checking if the substring is already in the result list.

  • Time Complexity: O(n^2 + n * m)
    • n^2: Traversal of the string pairs.
    • n * m: KMP substring matching.
  • Space Complexity: O(k + m)
    • k: Space used to store the result list.
    • m: Space used for the LPS array.

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
class Solution {
    public List<String> stringMatching(String[] words) {
        // Brute force (uncomment for use)
        // return bruteForce(words);

        // KMP algorithm
        int n = words.length;
        List<String> res = new ArrayList<>();
        
        for (int i = 0; i < n; i++) {
            String strI = words[i];

            for (int j = 0; j < n; j++) {
                if (i != j) {
                    String strJ = words[j];

                    // Check if strI is a substring of strJ using KMP
                    if (!res.contains(strI) && isSubstringKMP(strI, strJ)) {
                        res.add(strI);
                    }
                }
            }
        }

        return res;
    }

    // KMP Algorithm for substring matching
    public boolean isSubstringKMP(String pat, String text) {
        int patLen = pat.length();
        int textLen = text.length();
        
        if (patLen > textLen) {
            return false;
        }

        int[] lps = new int[patLen];
        computeLPS(pat, lps);

        int i = 0; // text pointer
        int j = 0; // pattern pointer

        while (i < textLen) {
            if (text.charAt(i) == pat.charAt(j)) {
                i++;
                j++;

                if (j == patLen) {
                    return true; // Pattern found
                }
            } else {
                if (j == 0) {
                    i++;
                } else {
                    j = lps[j - 1];
                }
            }
        }
        return false;
    }

    // Compute the LPS array for KMP
    public void computeLPS(String pat, int[] lps) {
        int len = 0;
        int i = 1;
        lps[0] = 0;

        while (i < pat.length()) {
            if (pat.charAt(i) == pat.charAt(len)) {
                len++;
                lps[i] = len;
                i++;
            } else {
                if (len == 0) {
                    lps[i] = 0;
                    i++;
                } else {
                    len = lps[len - 1];
                }
            }
        }
    }

    // Brute Force approach
    public List<String> bruteForce(String[] words) {
        int n = words.length;
        List<String> res = new ArrayList<>();

        for (int i = 0; i < n; i++) {
            String strI = words[i];

            for (int j = 0; j < n; j++) {
                if (i != j) {
                    String strJ = words[j];
                    if (strI.contains(strJ) && !res.contains(strJ)) {
                        res.add(strJ);
                    }
                }
            }
        }
        return res;
    }
}
This post is licensed under CC BY 4.0 by the author.