Find Beautiful Indices in the Given Array I

MEDIUM

Description

You are given a 0-indexed string s, a string a, a string b, and an integer k.

An index i is beautiful if:

  • 0 <= i <= s.length - a.length
  • s[i..(i + a.length - 1)] == a
  • There exists an index j such that:
    • 0 <= j <= s.length - b.length
    • s[j..(j + b.length - 1)] == b
    • |j - i| <= k

Return the array that contains beautiful indices in sorted order from smallest to largest.

 

Example 1:

Input: s = "isawsquirrelnearmysquirrelhouseohmy", a = "my", b = "squirrel", k = 15
Output: [16,33]
Explanation: There are 2 beautiful indices: [16,33].
- The index 16 is beautiful as s[16..17] == "my" and there exists an index 4 with s[4..11] == "squirrel" and |16 - 4| <= 15.
- The index 33 is beautiful as s[33..34] == "my" and there exists an index 18 with s[18..25] == "squirrel" and |33 - 18| <= 15.
Thus we return [16,33] as the result.

Example 2:

Input: s = "abcd", a = "a", b = "a", k = 4
Output: [0]
Explanation: There is 1 beautiful index: [0].
- The index 0 is beautiful as s[0..0] == "a" and there exists an index 0 with s[0..0] == "a" and |0 - 0| <= 4.
Thus we return [0] as the result.

 

Constraints:

  • 1 <= k <= s.length <= 105
  • 1 <= a.length, b.length <= 10
  • s, a, and b contain only lowercase English letters.

Approaches

Checkout 3 different approaches to solve Find Beautiful Indices in the Given Array I. Click on different approaches to view the approach and algorithm in detail.

Brute-Force Nested Loop

This approach is a straightforward, brute-force solution. It first identifies all occurrences of the substrings a and b within the main string s and stores their starting indices in two separate lists. Afterwards, it employs a pair of nested loops to compare every index from the first list against every index from the second. If any pair of indices (i, j) satisfies the condition |i - j| <= k, the index i is marked as beautiful and added to the result.

Algorithm

  • Create two lists, indicesA and indicesB, to store the starting indices of all occurrences of strings a and b in s.
  • Populate indicesA by iterating through s and checking for a at each position.
  • Populate indicesB similarly by checking for b.
  • Initialize an empty list result to store the beautiful indices.
  • Iterate through each index i in indicesA with an outer loop.
  • Inside, use a nested loop to iterate through each index j in indicesB.
  • If Math.abs(i - j) <= k, it means i is a beautiful index. Add i to result and break the inner loop to proceed to the next i.
  • Return the result list.

The implementation involves two main steps. First, we scan the string s twice to find all starting positions for a and b. A simple way to do this is by iterating from 0 to s.length() - pattern.length() and using s.startsWith(pattern, i). The found indices are stored in indicesA and indicesB.

Second, we iterate through each index i in indicesA. For each i, we iterate through all indices j in indicesB. We calculate the absolute difference |i - j| and check if it's less than or equal to k. If the condition holds, we add i to our result list and use break to stop searching for other j's for the current i, as one is sufficient.

import java.util.ArrayList;
import java.util.List;

class Solution {
    public List<Integer> beautifulIndices(String s, String a, String b, int k) {
        int n = s.length();
        int lenA = a.length();
        int lenB = b.length();

        List<Integer> indicesA = new ArrayList<>();
        for (int i = 0; i <= n - lenA; i++) {
            if (s.startsWith(a, i)) {
                indicesA.add(i);
            }
        }

        List<Integer> indicesB = new ArrayList<>();
        for (int i = 0; i <= n - lenB; i++) {
            if (s.startsWith(b, i)) {
                indicesB.add(i);
            }
        }

        List<Integer> result = new ArrayList<>();
        if (indicesA.isEmpty() || indicesB.isEmpty()) {
            return result;
        }

        for (int i : indicesA) {
            for (int j : indicesB) {
                if (Math.abs(i - j) <= k) {
                    result.add(i);
                    break; // Found a valid j, move to the next i
                }
            }
        }
        return result;
    }
}

Complexity Analysis

Time Complexity: O(N*M + P*Q), where N is `s.length()`, M is `max(a.length(), b.length())`, P is the count of `a`'s occurrences, and Q is the count of `b`'s occurrences. In the worst case, P and Q can be O(N), making the complexity O(N^2).Space Complexity: O(P + Q), where P and Q are the number of occurrences of `a` and `b` respectively. In the worst case, this can be O(N), where N is the length of `s`.

Pros and Cons

Pros:
  • Easy to understand and implement.
  • Works correctly for small inputs.
Cons:
  • The nested loop for checking the distance condition leads to a quadratic time complexity in the worst case, which is highly inefficient for large inputs.
  • It is likely to result in a 'Time Limit Exceeded' error on platforms with strict time constraints.

Code Solutions

Checking out 3 solutions in different languages for Find Beautiful Indices in the Given Array I. Click on different languages to view the code.


Video Solution

Watch the video walkthrough for Find Beautiful Indices in the Given Array I



Algorithms:

Binary Search

Patterns:

Two PointersString MatchingRolling HashHash Function

Data Structures:

String

Subscribe to Scale Engineer newsletter

Learn about System Design, Software Engineering, and interview experiences every week.

No spam, unsubscribe at any time.