Skip to main content

Conditional Substring Matching

By 2022-05-08Algorithm

Given m unique characters [a, b, c, d], and a string “tbcacbdata” of length n. Find a continuous substring s of “tbcacbdata” with length m, such that s only consists of all the characters in m, the order does not matter. Return any of the satisfied substring and the starting position of that substring, return -1 and an empty string if it is not found. For example, in the above example, one should return 3, “acbd”.

package main

import "fmt"

func main(){
    printOutput(find([]byte{'a','b','d'}, []byte{'t','b','c','a','c','b','d','a','t','a'}))

    printOutput(find([]byte{'a','b','d', 'c'}, []byte{'t','b','c','a','c','b','d','a','t','a'}))

    printOutput(find([]byte{'t','b','c'}, []byte{'t','b','c','a','c','b','d','a','t','a'}))

    printOutput(find([]byte{'t'}, []byte{'t','b','c','a','c','b','d','a','t','a'}))

    printOutput(find([]byte{'c','b','a'}, []byte{'t','b','c','a','c','b','d','a','t','a'}))

    printOutput(find([]byte{'t','a'}, []byte{'t','b','c','a','c','b','d','a','t','a'}))

    printOutput(find([]byte{'g'}, []byte{'t','b','c','a','c','b','d','a','t','a'}))
}

func find(a, b []byte) (int, string) {
    mapping := map[byte]bool{}
    // init
    for _, n := range a {
        mapping[n] = true
    }
    i := 0 // Sliding Window left
    for j := 0; j < len(b); j++ { // Sliding Window right
        v, ok := mapping[b[j]] // expand the window to the right
        if ok && v{ // if current character is in m has not yet been used
            // expand the window toward right untill reached the target size
            mapping[b[j]] = false // mark as used
            if j - i + 1 == len(a) { // exit condition: the window has the same size as m
                return i, string(b[i: j + 1])
            }
        } else if ok && !v { // if current character is in m and has been used, such as "cac"
            // update the left side of the winow: to the next of the position of the last appearance of current characters
            if _, okk := mapping[b[i]]; okk {
                for i <= j {
                    if b[i] != b[j]  {
                        mapping[b[i]] = true
                        i++
                    } else {
                        break
                    }
                }
                i++
            }
        } else { // if current character is NOT in m
            // update the left side of the window to the position of window right, and mark everything bEFORE the window right as unused
            for i <= j {
                if _, okk := mapping[b[i]]; okk {
                    mapping[b[i]] = true
                }
                i++
            }
        }
    }
    return -1, ""
}

func printOutput(pos int, str string){
    if pos == -1 {
        fmt.Printf("string not found\n")
    } else {
        fmt.Printf("start at pos: %d, string is: %s\n", pos, str)
    }
}

Leave a Reply