You are given two integer arrays a[] and b[]. Return all the starting indexes of all the occurrences of b[] as a subarray in a[].
Examples:
Input: a[] = [2, 4, 1, 0, 4, 1, 1], b[] = [4, 1]
Output: [1, 4]
Explanation: b[] occurs as a subarray in a[] from index 1 to 2 and from index 4 to 5.Input: a[] = [2, 4, 1, 0, 0, 3], b[] = [0]
Output: [3, 4]
Explanation: b[] occurs as a subarray in a[] from index 3 to 3 and from index 4 to 4.
Table of Content
[Naive Approach] Comparing All Subarrays - O(n * m) Time and O(1) Space
The idea is to check for all possible indices in a[] as starting index of subarray b[]. For each index, compare the subarray of a[] with b[] using a nested loop. If all the elements match, store the starting index in result. If any element does not match, break and check for next starting index.
Consider the following dry run: a = [2, 4, 1, 0, 4, 1, 1], b = [4, 1]
- For i = 0 --> (2 ≠ 4) --> mismatch --> move to next i
- For i = 1 --> (4 = 4, 1 = 1) --> match --> add index 1
- For i = 2 --> (1 ≠ 4) --> mismatch --> move to next i
- For i = 3 --> (0 ≠ 4) --> mismatch --> move to next i
- For i = 4 --> (4 = 4, 1 = 1) --> match --> add index 4
- For i = 5 --> (1 ≠ 4) --> mismatch --> move to next i
Final answer: [1, 4]
#include <iostream>
#include <vector>
using namespace std;
vector<int> search(vector<int> &a, vector<int> &b) {
int n = a.size(), m = b.size();
vector<int> res;
// Iterate over all possible
// starting indices
for(int i = 0; i < n - m + 1; i++) {
bool isSame = true;
for(int j = 0; j < m; j++) {
// If any character does not match, break
// and begin from the next starting index
if(a[i + j] != b[j]) {
isSame = false;
break;
}
}
// If all characters are matched, store the
// starting index
if(isSame)
res.push_back(i);
}
return res;
}
int main() {
vector<int> a = {2, 4, 1, 0, 4, 1, 1};
vector<int> b = {4, 1};
vector<int> res = search(a, b);
for(int idx: res)
cout << idx << " ";
}
import java.util.ArrayList;
class GfG {
static ArrayList<Integer> search(int[] a, int[] b) {
int n = a.length, m = b.length;
ArrayList<Integer> res = new ArrayList<>();
// Iterate over all possible
// starting indices
for (int i = 0; i <= n - m; i++) {
boolean isSame = true;
// Check if b matches starting
// from index i in a
for (int j = 0; j < m; j++) {
if (a[i + j] != b[j]) {
isSame = false;
break;
}
}
// If all elements matched,
// add starting index
if (isSame)
res.add(i);
}
return res;
}
public static void main(String[] args) {
int[] a = {2, 4, 1, 0, 4, 1, 1};
int[] b = {4, 1};
ArrayList<Integer> res = search(a, b);
for (int idx : res)
System.out.print(idx + " ");
}
}
def search(a, b):
n = len(a)
m = len(b)
res = []
# Iterate over all possible
# starting indices
for i in range(n - m + 1):
isSame = True
for j in range(m):
# If any character does not match, break
# and begin from the next starting index
if a[i + j] != b[j]:
isSame = False
break
# If all characters are matched,
# store the starting index
if isSame:
res.append(i)
return res
# Driver code
if __name__ == "__main__":
a = [2, 4, 1, 0, 4, 1, 1]
b = [4, 1]
res = search(a, b)
for idx in res:
print(idx, end=" ")
using System;
using System.Collections.Generic;
class GfG {
static List<int> search(int[] a, int[] b) {
int n = a.Length, m = b.Length;
List<int> res = new List<int>();
// Iterate over all possible
// starting indices
for (int i = 0; i < n - m + 1; i++) {
bool isSame = true;
for (int j = 0; j < m; j++) {
// If any character does not match, break
// and begin from the next starting index
if (a[i + j] != b[j]) {
isSame = false;
break;
}
}
// If all characters are matched,
// store the starting index
if (isSame)
res.Add(i);
}
return res;
}
public static void Main() {
int[] a = { 2, 4, 1, 0, 4, 1, 1};
int[] b = { 4, 1 };
List<int> res = search(a, b);
foreach (int idx in res) {
Console.Write(idx + " ");
}
}
}
function search(a, b)
{
let n = a.length, m = b.length;
let res = [];
// Iterate over all possible
// starting indices
for (let i = 0; i < n - m + 1; i++) {
let isSame = true;
for (let j = 0; j < m; j++) {
// If any character does not match, break
// and begin from the next starting index
if (a[i + j] !== b[j]) {
isSame = false;
break;
}
}
// If all characters are matched,
// store the starting index
if (isSame)
res.push(i);
}
return res;
}
// Driver code
let a = [ 2, 3, 0, 3, 0, 3, 0 ];
let b = [ 3, 0, 3, 0 ];
let res = search(a, b);
for (let idx of res) {
console.log(idx + " ");
}
Output
1 4
[Expected Approach] Using KMP Algorithm - O(m + n) Time and O(m) Space
The idea is to use the KMP algorithm by treating array
aas the text and arraybas the pattern. Instead of characters, we compare integers. We first build the LPS (Longest Prefix Suffix) array for the pattern, which helps us skip unnecessary comparisons when a mismatch occurs. Then, while scanning the text, we use this LPS information to efficiently find all occurrences of the pattern in O(n + m) time.
Consider this dry run for better understanding: a = [2, 4, 1, 0, 4, 1, 1], b = [4, 1]
- Step 0: Build LPS for b --> b = [4, 1] --> lps = [0, 0]
- Step 1: KMP Algorithm
For i = 0, j = 0 --> 2 ≠ 4 --> j = 0, i++
For i = 1, j = 0 --> 4 = 4 --> i = 2, j = 1
For i = 2, j = 1 --> 1 = 1 --> match --> add (2 - 2 = 1) --> j = 0
For i = 2, j = 0 --> 1 ≠ 4 --> i++
For i = 3, j = 0 --> 0 ≠ 4 --> i++
For i = 4, j = 0 --> 4 = 4 --> i = 5, j = 1
For i = 5, j = 1 --> 1 = 1 --> match --> add (5 - 2 = 4) --> j = 0
For i = 5, j = 0 --> 1 ≠ 4 --> i++
For i = 6, j = 0 --> 1 ≠ 4 --> i++
Final answer: [1, 4]
#include <iostream>
#include <vector>
using namespace std;
void constructLps(vector<int> &pat, vector<int> &lps)
{
// len stores the length of longest
// prefix which is also a suffix
// for the previous index
int len = 0;
// lps[0] is always 0
lps[0] = 0;
int i = 1;
while (i < pat.size())
{
// If numbers match, increment
// the size of lps
if (pat[i] == pat[len])
{
len++;
lps[i] = len;
i++;
}
else
{
if (len != 0)
{
// Update len to the previous lps value
// to avoid reduntant comparisons
len = lps[len - 1];
}
else
{
// If no matching prefix found,
// set lps[i] to 0
lps[i] = 0;
i++;
}
}
}
}
vector<int> search(vector<int> &a, vector<int> &b)
{
int n = a.size();
int m = b.size();
vector<int> lps(m);
vector<int> res;
constructLps(b, lps);
// Pointers i and j, for traversing
// a[] and b[]
int i = 0;
int j = 0;
while (i < n)
{
// If elements match, move
// both pointers forward
if (a[i] == b[j])
{
i++;
j++;
// If all elements of b[] are matched
// store the start index in result
if (j == m)
{
res.push_back(i - j);
// Use LPS of previous index to
// skip unnecessary comparisons
j = lps[j - 1];
}
}
// If there is a mismatch
else
{
// Use lps value of previous index
// to avoid redundant comparisons
if (j != 0)
j = lps[j - 1];
else
i++;
}
}
return res;
}
int main()
{
vector<int> a = {2, 4, 1, 0, 4, 1, 1};
vector<int> b = {4, 1};
vector<int> res = search(a, b);
for (int idx : res)
cout << idx << " ";
}
import java.util.ArrayList;
class GfG {
// Function to construct LPS array
static void constructLps(int[] pat, int[] lps)
{
// len stores the length of longest
// prefix which is also a suffix
// for the previous index
int len = 0;
// lps[0] is always 0
lps[0] = 0;
int i = 1;
while (i < pat.length) {
// If numbers match, increment
// the size of lps
if (pat[i] == pat[len]) {
len++;
lps[i] = len;
i++;
}
else {
if (len != 0) {
// Update len to the previous lps value
// to avoid reduntant comparisons
len = lps[len - 1];
}
else {
// If no matching prefix found,
// set lps[i] to 0
lps[i] = 0;
i++;
}
}
}
}
static ArrayList<Integer> search(int[] a, int[] b)
{
int n = a.length;
int m = b.length;
int[] lps = new int[m];
ArrayList<Integer> res = new ArrayList<>();
constructLps(b, lps);
int i = 0, j = 0;
// If elements match, move
// both pointers forward
while (i < n) {
if (a[i] == b[j]) {
i++;
j++;
// If all elements of b[] are matched
// store the start index in result
if (j == m) {
res.add(i - j);
j = lps[j - 1];
// Use LPS of previous index to
// skip unnecessary comparisons
}
}
else {
if (j != 0) {
j = lps[j - 1];
}
else {
i++;
}
}
}
return res;
}
public static void main(String[] args)
{
int[] a = { 2, 4, 1, 0, 4, 1, 1 };
int[] b = { 4, 1 };
ArrayList<Integer> res = search(a, b);
for (int idx : res)
System.out.print(idx + " ");
}
}
def constructLps(pat, lps):
# len stores the length of longest
# prefix which is also a suffix
# for the previous index
length = 0
# lps[0] is always 0
lps[0] = 0
i = 1
while i < len(pat):
# If numbers match, increment
# the size of lps
if pat[i] == pat[length]:
length += 1
lps[i] = length
i += 1
else:
if length != 0:
# Update length to the previous lps value
# to avoid redundant comparisons
length = lps[length - 1]
else:
# If no matching prefix found,
# set lps[i] to 0
lps[i] = 0
i += 1
def search(a, b):
n = len(a)
m = len(b)
lps = [0] * m
res = []
constructLps(b, lps)
# Pointers i and j, for
# traversing a[] and b[]
i = 0
j = 0
while i < n:
# If elements match, move both
# pointers forward
if a[i] == b[j]:
i += 1
j += 1
# If all elements of b[] are matched
# store the start index in result
if j == m:
res.append(i - j)
# Use LPS of previous index to
# skip unnecessary comparisons
j = lps[j - 1]
else:
# If there is a mismatch
# Use lps value of previous index
# to avoid redundant comparisons
if j != 0:
j = lps[j - 1]
else:
i += 1
return res
# Driver code
if __name__ == "__main__":
a = [2, 4, 1, 0, 4, 1, 1]
b = [4, 1]
res = search(a, b)
for idx in res:
print(idx, end=" ")
using System;
using System.Collections.Generic;
class GfG {
// Function to construct the LPS
// array (Longest Prefix Suffix)
static void ConstructLps(int[] pat, int[] lps)
{
// len stores the length of the longest
// prefix which is also a suffix
// for the previous index
int len = 0;
// lps[0] is always 0
lps[0] = 0;
int i = 1;
while (i < pat.Length) {
// If numbers match, increment the size of lps
if (pat[i] == pat[len]) {
len++;
lps[i] = len;
i++;
}
// If there is a mismatch
else {
if (len != 0) {
// Update len to the previous lps value
// to avoid redundant comparisons
len = lps[len - 1];
}
else {
// If no matching prefix found,
// set lps[i] to 0
lps[i] = 0;
i++;
}
}
}
}
// Function to search for the subarray
static List<int> search(int[] a, int[] b)
{
int n = a.Length;
int m = b.Length;
int[] lps = new int[m];
List<int> res = new List<int>();
ConstructLps(b, lps);
// Pointers i and j, for
// traversing a[] and b[]
int i = 0;
int j = 0;
while (i < n) {
// If elements match, move
// both pointers forward
if (a[i] == b[j]) {
i++;
j++;
// If all elements of b[] are matched
// store the start index in result
if (j == m) {
res.Add(i - j);
// Use LPS of previous index to
// skip unnecessary comparisons
j = lps[j - 1];
}
}
else {
// Use lps value of previous index
// to avoid redundant comparisons
if (j != 0)
j = lps[j - 1];
else
i++;
}
}
return res;
}
public static void Main()
{
int[] a = { 2, 4, 1, 0, 4, 1, 1 };
int[] b = { 4, 1 };
List<int> res = search(a, b);
foreach(int idx in res)
{
Console.Write(idx + " ");
}
}
}
// function to search subarray b in array a
function search(a, b)
{
let n = a.length;
let m = b.length;
let lps = new Array(m);
let res = [];
constructLps(b, lps);
// Pointers i and j, for traversing a[] and b[]
let i = 0;
let j = 0;
while (i < n) {
// If elements match, move
// both pointers forward
if (a[i] === b[j]) {
i++;
j++;
// If all elements of b[] are matched
// store the start index in result
if (j === m) {
res.push(i - j);
// Use LPS of previous index to
// skip unnecessary comparisons
j = lps[j - 1];
}
}
else {
// Use lps value of previous index
// to avoid redundant comparisons
if (j !== 0)
j = lps[j - 1];
else
i++;
}
}
return res;
}
// function to construct lps
function constructLps(pat, lps)
{
// len stores the length of longest prefix which
// is also a suffix for the previous index
let len = 0;
// lps[0] is always 0
lps[0] = 0;
let i = 1;
while (i < pat.length) {
// If numbers match, increment the size of lps
if (pat[i] === pat[len]) {
len++;
lps[i] = len;
i++;
}
else {
if (len !== 0) {
// Update len to the previous lps value
// to avoid redundant comparisons
len = lps[len - 1];
}
else {
// If no matching prefix found,
// set lps[i] to 0
lps[i] = 0;
i++;
}
}
}
}
// Driver Code
let a = [ 2, 4, 1, 0, 4, 1, 1 ];
let b = [ 4, 1 ];
let res = search(a, b);
let ans = "";
for (let idx of res) {
ans += idx + " ";
}
console.log(ans.trim());
Output
1 4
Related Topic: Subarrays, Subsequences, and Subsets in Array