Skip to content

Instantly share code, notes, and snippets.

@sharma-abhishek-it
Last active August 29, 2015 14:11
Show Gist options
  • Select an option

  • Save sharma-abhishek-it/b72a01bb651f4860a959 to your computer and use it in GitHub Desktop.

Select an option

Save sharma-abhishek-it/b72a01bb651f4860a959 to your computer and use it in GitHub Desktop.
Shuffle search substr
String::linear_search = (from,to,sub) ->
i = from
j = 0
max = sub.length
while (to - i + 1) >= (max-j)
if @[i] == sub[j]
i++; j++
else
j = 0; i++
return true if j == max
return false
# Algorithm description
# Summary: Instead of linearly searching for your substring whether it exists
# if we randomly search segments then it can have a better avg time
# The main recipe for random search will be:
# 1. Start with initial string as first segment
# 2. Choose the middle letter of this segment
# 3. If this letter exists in substring then
# 3.1 Find the bounds around this letter in which you should do linear
# search
# 3.2 Either your substr is within these bounds and if not then simply
# divide your segment into two by dividing on the segment you
# searched on
# 4. If this letter does not exist then simply divide into 2 segments
# 5 If segment has enough length then push them into segment lists
# 6. Got to step1 and randomly choose a segment
String::shuffle_search = (sub) ->
chars = {}
_.each sub, (v, i, arr) ->
chars[v] = {"first": i, "last": i} unless chars[v]
chars[v]["last"] = i
segments = []
segments.push {"begin": 0, "end": @length - 1}
found = false
max_len_sub = sub.length
until segments.length == 0 || found
randomSegment_i = Math.floor(Math.random() * segments.length)
segment = segments.splice(randomSegment_i, 1)[0]
continue if (segment["end"] - segment["begin"]) < max_len_sub
#randomChar_i=Math.floor(Math.random() *segment["end"])+segment["begin"]
randomChar_i = Math.floor((segment["end"] - segment["begin"]) / 2)
randomChar_i += segment["begin"]
c = @[randomChar_i]
if chars[c]
left_bound = randomChar_i - chars[c]["last"]
right_bound = randomChar_i + max_len_sub - chars[c]["first"]
virt_left_bound = if left_bound < segment["begin"]
segment["begin"]
else
if chars[@[left_bound]]
left_bound - chars[@[left_bound]]["last"]
else
left_bound
virt_left_bound = segment["begin"] if segment["begin"] > virt_left_bound
virt_right_bound = if right_bound > segment["end"]
segment["end"]
else
if chars[@[right_bound]]
right_bound + max_len_sub - chars[@[right_bound]]["first"]
else
right_bound
virt_right_bound = segment["end"] if segment["end"] < virt_left_bound
found = @linear_search virt_left_bound, virt_right_bound, sub
break if found
if left_bound - segment["begin"] >= max_len_sub
segments.push {"begin": segment["begin"], "end": left_bound - 1}
if segment["end"] - right_bound >= max_len_sub
segments.push {"begin": right_bound + 1, "end": segment["end"]}
else
if randomChar_i - segment["begin"] >= max_len_sub
segments.push {"begin": segment["begin"], "end": randomChar_i - 1}
if segment["end"] - randomChar_i >= max_len_sub
segments.push {"begin": randomChar_i + 1, "end": segment["end"]}
return found
describe "string shuffle search problem", ->
it "does linear search properly", ->
a = "1233456"
b = "334"
expect(a.linear_search 0, a.length-1, b).toBe(true)
a = "abcdedfgdfhaLMMNbcd"
b = "LMMN"
expect(a.linear_search 0, a.length-1, b).toBe(true)
it "detects presence", ->
a = "abcdedfgdfhaLMMNbcd"
b = "LMMN"
expect(a.shuffle_search b).toBe(true)
it "detects absence", ->
a = "abcdedfgdhabcd"
b = "LMMN"
expect(a.shuffle_search b).toBe(false)
it "compares better to linear search", ->
[a,b] = ["",""]
_.times 9000000*2, ->
a += String.fromCharCode(Math.floor(Math.random()*25)+97)
_.times 9800, ->
b += String.fromCharCode(Math.floor(Math.random()*25)+65)
a += b
_.times 1000000*2, ->
a += String.fromCharCode(Math.floor(Math.random()*25)+97)
t1 = new Date()
r1 = a.linear_search 0, a.length-1, b
t2 = new Date()
r2 = a.shuffle_search b
t3 = new Date()
expect(r1).toBe(true)
expect(r2).toBe(true)
console.log "\nTime taken linear- #{(t2 - t1)/1000}s shuffle- #{(t3 - t2)/1000}s"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment