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

©️ 2021 Arctic Kingdom. All right reserved.

Close Menu