<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-10096563</id><updated>2025-09-25T08:09:53.287-07:00</updated><category term="algorithms"/><category term="data structures"/><category term="tech"/><category term="code"/><category term="puzzles"/><category term="humor"/><category term="thoughts"/><category term="installation"/><category term="books"/><category term="projects"/><category term="design"/><category term="news"/><category term="wish"/><title type='text'>RM</title><subtitle type='html'>dumb Software Engineer</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>RM</name><uri>http://www.blogger.com/profile/17713440099650366770</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>239</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-10096563.post-7224984499037422427</id><published>2020-07-03T12:00:00.000-07:00</published><updated>2020-07-03T14:48:02.748-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>calc grid min given directions</title><content type='html'>Calculate min for a grid starting from top row and going down in 3 directions (down-left, down, down-right).
&lt;br /&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
00 01 02 -&gt; j
10 11 12
20 21 22
&lt;/pre&gt;

&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;calcMin(grid):
    if grid == null
        || grid.length() == 0
        || grid[0].length() == 0:
        throw
    rows = grid.length()
    cols = grid[0].length()
    mins = new [rows, cols]
    calcMins(grid, rows, cols, mins)
    min = getMin(mins, cols)
    return min

calcMins(grid, rows, cols, mins):
    for i = 0, i &lt; rows, i++:
        calcMin(grid, rows, cols, i, 0, mins)

calcMin(grid, rows, cols, i, j, mins):
    if !(0 &lt;= i &lt; rows):
        return null
    if !(0 &lt;= j &lt; cols):
        return null
    if mins[i][j] != null:
        return mins[i][j]
    min =
        checked(
            grid[i][j]
                + min(
                    calcMin(grid, rows, cols, i+1, j-1], mins),
                    calcMin(grid, rows, cols, i+1,   j], mins),
                    calcMin(grid, rows, cols, i+1, j+1], mins)
                    )
            )
    mins[i][j] = min
    return min

min(a, b, c):
    if a == null &amp;&amp; b == null &amp;&amp; c == null:
        return 0
    return
        math.min(
            a ?? int.max,
            b ?? int.max,
            c ?? int.max
            )

getMin(mins, cols):
    min = mins[0][0]
    for j = 1, j &lt; cols, j++:
        min = math.min(min, mins[0][j])
    return min
&lt;/pre&gt;

[Hat tip to SM]
</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/7224984499037422427/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2020/07/calc-grid-min-given-directions.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/7224984499037422427'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/7224984499037422427'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2020/07/calc-grid-min-given-directions.html' title='calc grid min given directions'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-2180083573931442815</id><published>2020-01-15T02:00:00.000-08:00</published><updated>2020-07-03T23:20:48.656-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>batching items with batch.tryAdd(item)</title><content type='html'>Process items in batches with bool batch.tryAdd(item).
&lt;br /&gt;
&lt;br /&gt;
This is a bit clunky as it mixes the batch population and sending.
&lt;br /&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;process(sender, items):
    batch = new
    for item in items:
        if !batch.tryAdd(item):
            if batch.any():
                sender.send(batch)
            batch = new
            if !batch.tryAdd(item):
                // poison message
                throw
    if batch.any():
        sender.send(batch)
&lt;/pre&gt;
Better as batch population is separated out.
&lt;br /&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;process(sender, items):
    i = 0
    while i &amp;lt; items.count():
        batch = new
        while i &amp;lt; items.count() &amp;amp;&amp;amp; batch.tryAdd(items[i]):
            i++
        if !batch.any():
            // poison message
            throw
        sender.send(batch)
&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/2180083573931442815/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2020/01/batching-items-with-batch-try-add-item.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/2180083573931442815'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/2180083573931442815'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2020/01/batching-items-with-batch-try-add-item.html' title='batching items with batch.tryAdd(item)'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-6931841396748333482</id><published>2019-12-14T01:00:00.000-08:00</published><updated>2025-09-24T13:35:51.208-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>find x in non-overlapping ranges</title><content type='html'>&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &amp;quot;Andale Mono&amp;quot;, &amp;quot;Lucida Console&amp;quot;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;range:
    min
    max

// pre-condition: ranges are sorted and are not overlapping
// O(logn)
range find(x, ranges):
    if ranges == null:
        throw
    if ranges.isEmpty():
        return nullRange
    return findInner(x, ranges)

// O(nlogn)
sort(ranges):
    ranges = ranges.sort(x =&amp;gt; x.min)

// ranges need to be sorted
// O(n)
validate(ranges):
    if ranges.isEmpty():
        return
    prevRange = ranges[0]
    for i = 1, i &amp;lt; ranges.count(), i++:
        range = ranges[i]
        if !(prevRange.max &amp;lt; range.min):
            throw
        prevRange = range

// O(logn)
findInner(x, ranges):
    start = 0
    end = ranges.count() -1
    while start &amp;lt;= end:
        mid = start + (end-start)/2
        range = ranges[mid]
        if x &amp;lt; range.min:
            end = mid -1
        else if x &amp;gt; range.max:
            start = mid +1
        else:
            return range
    return nullRange
&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/6931841396748333482/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2019/12/find-x-in-non-overlapping-ranges.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/6931841396748333482'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/6931841396748333482'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2019/12/find-x-in-non-overlapping-ranges.html' title='find x in non-overlapping ranges'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-9059647798322077738</id><published>2019-10-07T09:00:00.000-07:00</published><updated>2019-12-16T01:18:15.225-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>polly simple circuit breaker</title><content type='html'>- Break (or open) circuit on consecutive &#39;n&#39; handled exception or handled result for breakDuration interval. Throw brokenCircuitEx when circuit is open.&lt;br /&gt;
- When circuit is open and breakDuration has elapsed, the circuitBreaker goes into half-open state. Sample the next call:&lt;br /&gt;
&amp;nbsp; &amp;nbsp; - If it succeeds, close the circuit.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; - If it fails (throws handled ex or handled result), break the circuit again.&lt;br /&gt;
- An unhandled ex does not alter the circuit state. An unhandled result closes the circuit.&lt;br /&gt;
- The ex or result that breaks the circuit is always thrown or returned. brokenCircuitEx is thrown on the next call.&lt;br /&gt;
- When throwing brokenCircuitEx, wrap the last exception or last result that broke the circuit.&lt;br /&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;// polly circuit breaker
brokenAt = null
count = 0

pollyCircuitBreaker_Execute(
        work, threshold, breakDuration,
        handlesException, handlesResult):
    lock(_lock):
        try:
            if isOpen():
                if lastHandledEx != null:
                    throw brokenCircuitEx(lastHandledEx)
                if lastHandledResult != null:
                    throw brokenCircuitEx(lastHandledResult)
                throw invalidStateEx()
            result = work()
            if handlesResult(result):
                if isHalfOpen():
                    breakCircuit()
                    lastHandledResult = result
                    return result
                if isClosed():
                    count++
                    if thresholdReached():
                        breakCircuit()
                        lastHandledResult = result
                    return result
                throw unsupportedEnumEx()
            // unhandled result
            closeCircuit()
            return result
        catch ex:
            if handlesException(ex):
                if isHalfOpen():
                    breakCircuit()
                    lastHandledEx = ex
                    throw
                if isClosed():
                    count++
                    if thresholdReached():
                        breakCircuit()
                        lastHandledEx = ex
                    throw
                throw unsupportedEnumEx()
            // unhandled ex
            throw

bool thresholdReached():
    return count == threshold
breakCircuit():
    brokenAt = now()
closeCircuit():
    brokenAt = null
    count = 0
    lastHandledEx = null
    lastHandledResult = null

bool isOpen():
    if isClosed():
        return false
    return brokenAt + breakDuration &amp;gt;= now()
bool isHalfOpen():
    if isClosed():
        return false
    return brokenAt + breakDuration &amp;lt; now()
bool isClosed():
    return brokenAt == null
&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/9059647798322077738/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2019/10/polly-simple-circuit-breaker.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/9059647798322077738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/9059647798322077738'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2019/10/polly-simple-circuit-breaker.html' title='polly simple circuit breaker'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-8539937726796718355</id><published>2019-09-28T11:00:00.000-07:00</published><updated>2019-10-29T23:44:22.494-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="code"/><title type='text'>REST idempotency for long running jobs</title><content type='html'>scenarios:
&lt;br /&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;- POST 202
  GET  404, 200

- POST 409

- POST 202
  GET  500
  retry POST

- POST 500
  retry POST
&lt;/pre&gt;
Due to two operations (cache, queue) there is a possibility of inconsistent state where the cache operation succeeds but the queue operation fails. One way to deal is to do a compensation operation (cache undo).&lt;br /&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;// post
response accept(request):
    item = cache.get(request.id)
    hash = hasher(request.id, request.body,
                  request.header1, request.header2, ...)
    if item == null:
        cache.insert({ id: request.id,
                       hash: hash })
        queue.send(request)
        return { statusCode: 202,
                 location: &quot;{request.id}/status&quot; }
    if hash != item.hash:
        return { statusCode: 409 }
    if item.statusCode == 5xx:
        updateItem(item)
        queue.send(request)
    return { statusCode: 202,
             location: &quot;{request.id}/status&quot; }

updateItem(item):
    item.statusCode = null
    cache.update(item)

// get
response status(id):
    item = store.get(id)
    return { statusCode: 200,
             code: item.statusCode,
             body: item.body }

// cache ttl exceeds possible retry window
cache:
    item get(id):
    insert(item):
    update(item):

store:
    item get(id):

hasher(request):
    // sha1 hash
&lt;/pre&gt;
This deals with the inconsistent state mentioned above but is unable to handle 409 conflicts in the backend. The chance of id collision is quite less. It is mainly an attack vector (attacker uses the same id but different bodies for requests in quick succession).&lt;br /&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;// post
response accept(request):
    item = cache.get(request.id)
    if item == null || item.statusCode == 5xx:
        queue.send(request)
        return { statusCode: 202,
                 location: &quot;{request.id}/status&quot; }
    hash = hasher(request.id, request.body,
                  request.header1, request.header2, ...)
    if hash != item.hash:
        return { statusCode: 409 }
    return { statusCode: 202,
             location: &quot;{request.id}/status&quot; }

// backend
process(request):
    item = cache.get(request.id)
    if item != null &amp;&amp; item.processing:
        // drop message
        return
    if item == null:
        hash = hasher(request.id, request.body,
                      request.header1, request.header2, ...)
        cache.insert({ id: request.id,
                       hash: hash,
                       processing: true })
    // can&#39;t deal with 409 here
    if item.statusCode == 5xx:
        item.statusCode = null
        item.processing = true
        cache.updateItem(item)
    processInner(request)

// get
response status(id):
    item = store.get(id)
    return { statusCode: 200,
             code: item.statusCode,
             body: item.body }

// cache ttl exceeds possible retry window
cache:
    item get(id):
    insert(item):
    update(item):

store:
    item get(id):

hasher(request):
    // sha1 hash
&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/8539937726796718355/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2019/09/rest-idempotency-for-long-running-jobs.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/8539937726796718355'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/8539937726796718355'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2019/09/rest-idempotency-for-long-running-jobs.html' title='REST idempotency for long running jobs'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-7339034632855194753</id><published>2019-09-19T21:00:00.000-07:00</published><updated>2019-10-19T18:19:34.198-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>dial</title><content type='html'>&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;rng = new

// dialValue: 0 - 100%
bool toDial(dialValue):
    if !(0 &lt;= dialValue &lt;= 100):
        throw
    r = rng.next(100) +1
    return r &lt;= dialValue

// dialValue: 0.00 - 100.00%
bool toDial(dialValue):
    if !(0 &lt;= dialValue &lt;= 100):
        throw
    r = (rng.next(100_00) /100.0) +.01
    return r &lt;= dialValue
&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/7339034632855194753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2019/09/dial.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/7339034632855194753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/7339034632855194753'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2019/09/dial.html' title='dial'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-1135821068347993213</id><published>2019-08-06T01:00:00.002-07:00</published><updated>2021-05-10T15:16:54.624-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>polly retry</title><content type='html'>&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;// polly retry
pollyRetry_ExecuteAndCapture(
        work, retryCount, delayer,
        handlesException, handlesResult):
    pollyResult = new
    for i = 0, i &amp;lt;= retryCount, i++:
        // default if success or ends in exception
        pollyResult.finalHandledResult  = default
        pollyResult.finalException      = default
        pollyResult.faultType           = default
        pollyResult.exceptionType       = default
        if i &amp;gt; 0:
            delay(delayer(i))
        try:
            result = work()
            if handlesResult(result):
                pollyResult.outcome = outcome.failure
                pollyResult.faultType = faultType.handledResult
                pollyResult.finalHandledResult = result
                // retry
                continue
            else:
                pollyResult.outcome = outcome.successful
                pollyResult.result = result
                break
        catch ex:
            pollyResult.finalException = ex
            if handlesException(ex):
                pollyResult.outcome = outcome.failure
                pollyResult.faultType = faultType.handledException
                pollyResult.exceptionType = exceptionType.handled
                // swallow, retry
                continue
            else:
                // do not throw
                pollyResult.outcome = outcome.failure
                pollyResult.faultType = faultType.unhandledException
                pollyResult.exceptionType = exceptionType.unhandled
                break
    return pollyResult
&lt;/pre&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;// polly retry
pollyRetry_Execute(
        work, retryCount, delayer,
        handlesException, handlesResult):
    pollyResult = pollyRetry_ExecuteAndCapture(work, retryCount, delayer,
        handlesException, handlesResult)
    if pollyResult.finalException != null:
        throw pollyResult.finalException
    return pollyResult.result
&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/1135821068347993213/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2019/08/polly-retry.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/1135821068347993213'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/1135821068347993213'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2019/08/polly-retry.html' title='polly retry'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-9165844608404465210</id><published>2018-04-16T09:00:00.000-07:00</published><updated>2018-04-16T09:00:12.738-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>find min in rotated array</title><content type='html'>&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
se
m
12
21

sme
123
231
312
&lt;/pre&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
int findMinRotated(a, start = 0, end = a.length() -1):
    if start &gt; end:
        throw
    if start == end:
        return a[start]
    if start +1 == end:
        return min(a[start], a[end])
    mid = start + (end-start)/2
    if a[start] &lt; a[mid] &lt; a[end]:
        return a[start]
    if a[start] &lt; a[mid]:
        return findMinRotated(a, mid, end)
    if a[mid] &lt; a[end]:
        return findMinRotated(a, start, mid)
    throw
&lt;/pre&gt;
[Hat tip to JR]</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/9165844608404465210/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2018/04/find-min-in-rotated-array.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/9165844608404465210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/9165844608404465210'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2018/04/find-min-in-rotated-array.html' title='find min in rotated array'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-4998896051700802468</id><published>2018-03-26T23:00:00.000-07:00</published><updated>2019-01-31T14:40:52.473-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>find path out of a maze</title><content type='html'>For left, right, up, down directions.
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
path maze(m, r = 0, c = 0):
    if m == null || m.length() == 0 || m[0].length() == 0:
        throw
    rows = m.length()
    cols = m[0].length()
    path = new
    mazeInner(m, r, c, rows, cols, path)
    return path

bool mazeInner(m, r = 0, c = 0, rows, cols,
    path, blocked = new bool[rows][cols]):
    if !(0 &lt;= r &lt; rows) || !(0 &lt;= c &lt; cols):
        return false
    if hasObstacle(m, r, c):
        return false
    if blocked[r][c]:
        return false
    if path.has(r, c):
        return false
    path.add((r, c))
    if isExit(m, r, c):
        return true
    if (m, r+1, c, rows, cols, path, visited):
        return true
    if (m, r-1, c, rows, cols, path, visited):
        return true
    if (m, r, c+1, rows, cols, path, visited):
        return true
    if (m, r, c-1, rows, cols, path, visited):
        return true
    path.removeLast()
    blocked[r][c] = true
    return false

bool isObstacle(m, r, c):
    return m[r][c] == -1
bool isExit(m, r, c):
    return m[r][c] == 1
&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/4998896051700802468/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2018/03/find-path-out-of-maze.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/4998896051700802468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/4998896051700802468'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2018/03/find-path-out-of-maze.html' title='find path out of a maze'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-2645791437196636668</id><published>2018-03-24T00:00:00.000-07:00</published><updated>2019-01-21T20:37:22.946-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><category scheme="http://www.blogger.com/atom/ns#" term="data structures"/><title type='text'>binary tree iterators</title><content type='html'>&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
binarytreeIterator:
    stack, prevn
    ctor(tree):
        if tree == null:
            throw
        stack = new
        prevn = null
        if tree.root != null:
            stack.push(tree.root)
    
    bool hasnext():
        return stack.any()
    
    //O(n)
    bool isVisited(n, visited):
        return visited.has(n)
    
    //O(1), and O(logn) due to stack
    bool isVisited(n, prevn):
        return prevn == n
    
    // pre-order
    x current():
        if stack.isEmpty():
            throw &quot;empty&quot;
        n = stack.pop()
        if n.right != null:
            stack.push(n.right)
        if n.left != null:
            stack.push(n.left)
        return n.value
        
    // in-order
    x current():
        if stack.isempty():
            throw &quot;empty&quot;
        while stack.any():
            n, isVisited = stack.pop()
            if !isVisited &amp;&amp; n.left != null:
                stack.push(n, isVisited: true)
                stack.push(n.left, isVisited: false)
                continue
            if n.right != null:
                stack.push(n.right, isVisited: false)
            return n
    
    // post-order
    x current():
        if stack.isEmpty():
            throw &quot;empty&quot;
        while stack.any():
            n = stack.pop()
            if n.left != null 
                &amp;&amp; !isVisited(n.left, prevn) &amp;&amp; !isVisited(n.right, prevn):
                stack.push(n)
                stack.push(n.left)
                continue
            if n.right != null &amp;&amp; !isVisited(n.right, prevn):
                stack.push(n)
                stack.push(n.right)
                continue
            prevn = n
            return n.value
        throw &quot;invalid op&quot;
&lt;/pre&gt;
[Hat tip to J]</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/2645791437196636668/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2018/03/binary-tree-iterators.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/2645791437196636668'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/2645791437196636668'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2018/03/binary-tree-iterators.html' title='binary tree iterators'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-2361741946188526665</id><published>2018-03-05T00:00:00.000-08:00</published><updated>2018-03-08T09:37:34.132-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>find x in sorted matrix</title><content type='html'>Find x in sorted matrix (last element of row is less than first element of next row).
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;(row, col) find(matrix, x):
    if matrix == null
        || matrix.length() == 0
        || matrix[0].length() == 0:
        throw
    rows = matrix.length()
    cols = matrix[0].length()
    len = rows * cols
    start = 0, end = len -1
    while start &lt;= end:
        mid = start + (end - start)/2
        i, j = toij(mid, cols)
        if x &lt; matrix[i][j]:
            end = mid -1
        else if matrix[i][j] &lt; x:
            start = mid +1
        else:
            return (i, j)
    return null

(i, j) toij(mid, cols):
    return (mid /cols, mid %cols)
&lt;/pre&gt;
[Hat tip to DJ]</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/2361741946188526665/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2018/03/find-x-in-sorted-matrix.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/2361741946188526665'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/2361741946188526665'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2018/03/find-x-in-sorted-matrix.html' title='find x in sorted matrix'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-3325770583352984862</id><published>2017-11-13T10:00:00.000-08:00</published><updated>2019-01-29T19:06:58.235-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="data structures"/><title type='text'>ordered hashset</title><content type='html'>&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
OrderedHashSet:
    map     // {T, {node{T}}
    dq      // {T}
    add(x):
        if has(x):
            // don&#39;t change position in queue
            // as it&#39;s a subtle behavior, instead let
            // the caller explicity call remove(x) and add(x)
            return
        map[x] = dq.enqueue(x)
    bool has(x):
        return map.hasKey(x)
    bool remove(x):
        if !has(x):
            return false
        dq.removeNode(map[x])
        map.remove(x)
        return true
    [] foreach():
        for x in dq:
            yield x

// deque interface
dq:
    node enqueue(x):
    bool removeNode(node):
&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/3325770583352984862/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2017/11/ordered-hashset.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/3325770583352984862'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/3325770583352984862'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2017/11/ordered-hashset.html' title='ordered hashset'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-8413059321009511419</id><published>2017-11-12T18:00:00.000-08:00</published><updated>2017-11-12T18:00:11.914-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>find shortest path for steps with obstacles</title><content type='html'>[0] is for step 1 and [n-1] for step n.
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
    i: 01   n = 2, length = 2
 step: 12   
value:      x don&#39;t care
&lt;/pre&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
steps findBestPath(obstacles, steps):
    if obstacles == null || obstacles.length() == 0:
        throw
    if steps.any(step &lt;= 0):
        throw
    sortDesc(steps)
    best = new
    findBestPath(obstacles, steps, best)
    return best

findBestPath(obstacles, steps, best, i = a.length()):
    if i == 0:
        return true
    if hasObstacle(obstacles, i):
        return false
    for step in steps:
        best.add(step)
        if findBestPath(obstacles, steps, best, i -step):
            return true
        best.removeLast(step)
    return false

bool hasObstacle(obstacles, i):
    if !(1 &lt;= i &lt;= a.length()):
        return false
    return obstacles[i-1]
&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/8413059321009511419/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2017/11/find-shortest-path-for-steps-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/8413059321009511419'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/8413059321009511419'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2017/11/find-shortest-path-for-steps-with.html' title='find shortest path for steps with obstacles'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-9217668750609655370</id><published>2017-11-07T23:00:00.001-08:00</published><updated>2020-10-16T13:03:23.538-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>first unique char in string</title><content type='html'>&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
char? (s):
    if s == null:
        throw
    countMap = new
    for c in s:
        countMap.tryGetValue(c, out count)
        countMap[c] = count +1
    for c in s:
        if countMap[c] == 1:
            return c
    return null
&lt;/pre&gt;

&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
char? (s):
    if s == null:
        throw
    unique = new
    repeating = new
    for c in s:
        if repeating.has(c):
            // do nothing
        else if unique.has(c):
            unique.remove(c)
            repeating.add(c)
        else:
            unique.add(c)
    for c in s:
        if unique.has(c):
            return c
    return null
&lt;/pre&gt;

&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;char? (s):
    if s == null:
        throw
    dq = new            //{char}
    chToNodeMap = new   //{char, node{char}}
    repeating = new     //{char}
    for c in s:
        if repeating.has(c): // 3+ hit
            // do nothing
        else if chnodeMap.hasKey(c): // 2nd hit
            repeating.add(c)
            dq.deleteNode(chnodeMap[c])
            chnodeMap.removeKey(c)
        else: // 1st hit
            chnodeMap[c] = dq.enqueue(c)
    if dq.isEmpty():
        return null
    return dq.peek()

deque:
    node enqueue(T)
    bool deleteNode(node)
    T peek()
    bool isEmpty()
&lt;/pre&gt;
[Hat tip to MC]

&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
// a        a
// abc      a
// aba      b
// abb      a
// abcbab   c
// aabb     null
char? (s):
    if s == null:
        throw
    consumed = new
    for i = s.length() -1, i &gt;= 0, i--:
        c = s[i]
        if consumed.has(c):
            if firstUniqueChar == c:
                firstUniqueChar = null
        else:
            consumed.add(c)
            firstUniqueChar = c
    return firstUniqueChar
&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/9217668750609655370/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2017/11/first-unique-char-in-string.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/9217668750609655370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/9217668750609655370'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2017/11/first-unique-char-in-string.html' title='first unique char in string'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-5342685861060913370</id><published>2017-11-03T14:00:00.000-07:00</published><updated>2017-11-03T14:00:28.674-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>swap matrix along diagonal</title><content type='html'>&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;00 01 02 03 04
10 11 12 13 14
20 21 22 23 24
30 31 32 33 34
40 41 42 43 44
&lt;/pre&gt;&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;swapRightDiagonal(m):
    // no throw for n = 0
    if m == null ||
        (m.length() &gt; 0 &amp;&amp; m.length() != m[0].length()):
        throw
    n = m.length()
    ni = n -1
    for layer = 0, layer &lt; n/2, layer++:
        swap(m, layer, layer, ni -layer, ni -layer)
        for i = layer +1, i &lt; ni -layer, i++:
            swap(m, layer, i, ni -i, ni -layer)
            swap(m, i, layer, ni -layer, ni -i)

swapLeftDiagonal(m):
    // no throw for n = 0
    if m == null ||
        (m.length() &gt; 0 &amp;&amp; m.length() != m[0].length()):
        throw
    n = m.length()
    ni = n -1
    for layer = 0, layer &lt; n/2, layer++:
        swap(m, ni -layer, layer, layer, ni -layer)
        for i = layer +1, i &lt; ni -layer, i++:
            swap(m, i, layer, layer, i)
            swap(m, ni -layer, i, i, ni -layer)

swap(m, ai, aj, bi, bj):
    temp = m[ai][aj]
    m[ai][aj] = m[bi][bj]
    m[bi][bj] = temp
&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/5342685861060913370/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2017/11/swap-matrix-along-diagonal.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/5342685861060913370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/5342685861060913370'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2017/11/swap-matrix-along-diagonal.html' title='swap matrix along diagonal'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-9187837456005344778</id><published>2017-11-03T03:00:00.000-07:00</published><updated>2017-11-03T19:32:37.256-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>rotate matrix</title><content type='html'>clockwise 90 degrees.&lt;br /&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;m
00 01 02 03
10 11 12 13
20 21 22 23
30 31 32 33

// right = top
00 01 02 03
         13
         23
&lt;/pre&gt;&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;rotate90C(m):
    // no throw for n = 0
    if m == null || 
        (m.length() &gt; 0 &amp;&amp; m.length() != m[0].length()):
        throw
    n = m.length()
    for layer = 0, layer &lt; n/2, layer++:
        for i = layer, i &lt; n-1 -layer, i++:
            // temp = top
            temp = m[layer][i]
            // top = left
            m[layer][i] = m[n-1-i][layer]
            // left = bottom
            m[n-1-i][layer] = m[n-1-layer][n-1-i]
            // bottom = right
            m[n-1-layer][n-1-i] = m[i][n-1-layer]
            // right = temp
            m[i][n-1-layer] = temp
&lt;/pre&gt;
[Hat tip to ctci]&lt;br&gt;
&lt;br&gt;
180 degrees.
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;rotate180(m):
    // no throw for n = 0
    if m == null || 
        (m.length() &gt; 0 &amp;&amp; m.length() != m[0].length()):
        throw
    for layer = 0, layer &lt; n/2, layer++:
        for i = layer, i &lt; ni -layer, i++:
            // top - bottom
            swap(m, layer, i, ni -layer, ni -i)
            // left - right
            swap(m, i, ni -layer, ni -i, layer)
&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/9187837456005344778/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2017/11/rotate-matrix.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/9187837456005344778'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/9187837456005344778'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2017/11/rotate-matrix.html' title='rotate matrix'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-984279742228568537</id><published>2017-11-01T18:00:00.000-07:00</published><updated>2018-02-21T22:01:28.640-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="data structures"/><title type='text'>implement hashmap</title><content type='html'>k cannot be null as cannot calculate hash of k. &lt;br /&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;hashmap:
    store = new // deque{{k, v}}[]
    
    add(k, v):
        i = index(k)
        dq = store[i]
        if dq == null:
            dq = new dq()
            store[i] = dq
        for kv in dq:
            if kv.key == k:
                kv.value = v
                return
        dq.enqueue(new {k, v})
    
    bool hasKey(k):
        dq = store[index(k)]
        if dq == null:
            return false
        for kv in dq:
            if kv.key == k:
                return true
        return false
    
    bool removeKey(k):
        i = index(k)
        dq = store[i]
        if dq == null:
            return false
        // dq.nodes() is a copy
        for node in dq.nodes():
            if node.kv.key == k:
                dq.removeNode(node)
                if dq.isEmpty():
                    store[i] = null
                return true
        return false
    
    // O(n)
    bool remove(v):
        for i = 0, i &lt; store.length(), i++:
            dq = store[i]
            if dq == null:
                continue
            // dq.nodes() is a copy
            for node in dq.nodes():
                if node.kv.value == v:
                    dq.removeNode(node)
                    if dq.isEmpty():
                        store[i] = null
                    return true
        return false
    
    // helpers
    int index(k):
        return hash(k) %store.length()
    int hash(k):
        if k == null:
            throw
        // ...
&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/984279742228568537/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2017/11/implement-hashmap.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/984279742228568537'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/984279742228568537'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2017/11/implement-hashmap.html' title='implement hashmap'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-6613869433964730662</id><published>2017-11-01T11:00:00.000-07:00</published><updated>2017-11-01T17:09:23.844-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>top k facebook friends of a user</title><content type='html'>dfs using a minheap.&lt;br /&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;// dfs, time: O(nlogk), space: O(k + logn + n)
[] top(user, k):
    if user == null || k &lt; 0:
        throw
    if k == 0:
        return []
    best = new minheap(capacity: k)
    set visited = new
    visited.add(user)
    for friend in user.friends():
        top(friend, k, best, visited)
    return best

top(user, k, best, visited):
    if visited.has(user):
        return
    visited.add(user)
    if best.count() == k:
        if user.rating() &gt; best.top().rating():
            best.displace(user)
    else:
        best.insert(user)
    for friend in user.friends():
        top(friend, k, best, visited)

minheap:
    insert(x):
    // return current top, replace it with x and heapify
    x displace(x):
    x top(): // or peek()
&lt;/pre&gt;bfs.&lt;br /&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;// bfs, time: O(nlogk), space: O(k + n)
[] top(user, k):
    if user == null || k &lt; 0:
        throw
    if k == 0:
        return []
    best = new minheap(capacity: k)
    set visited = new
    visited.add(user)
    q = new
    for friend in user.friends():
        q.enqueue(friend)
    top(k, best, q, visited)
    return best

top(k, best, q, visited):
    while !q.isEmpty():
        user = q.dequeue()
        if visited.has(user):
            continue
        visited.add(user)
        if best.count() == k:
            if user.rating() &gt; best.top().rating():
                best.displace(user)
        else:
            best.insert(user)
        for friend in user.friends():
            q.enqueue(friend)
&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/6613869433964730662/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2017/11/top-k-facebook-friends-of-user.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/6613869433964730662'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/6613869433964730662'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2017/11/top-k-facebook-friends-of-user.html' title='top k facebook friends of a user'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-2813968540287373130</id><published>2017-10-26T23:00:00.000-07:00</published><updated>2018-03-06T09:47:55.928-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>combinations with duplicates</title><content type='html'>&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;For aaaa,
a
aa
aaa
aaaa

a               a
    a           aa
        a       aaa
            a   aaaa
        a X
    a X
    a X
a X
a X
a X

For aaab,
a
aa
aaa
ab
aab
aaab
b

a               a
    a           aa
        a       aaa
            b   aaab
        b       aab
    a X         aa      X
        b       aab     X
    b           ab
a X             a       X
    a           aa      X
        b       aab     X
    b           ab      X
a X             a       X
    b           ab      X
b               b
&lt;/pre&gt;
Sort the characters in s so dupes are adjacent to each. The 1st iteration needs to go through and skip the 2nd iteration onward for dupes.
&lt;br /&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
// in is sorted
combineWithDupes(in, start = 0, buffer, items)
    if start &amp;gt; 0:
        items.add(buffer.toString())
    for i = start, i &amp;lt; in.length(), i++:
        if i &amp;gt; start &amp;amp;&amp;amp; a[i-1] == a[i]:
            continue
        buffer.append(in[i])
        combineWithDupes(in, i +1, buffer, items)`
        buffer.removeLast()
&lt;/pre&gt;
Bottom-up:
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
// in is sorted
[] combineWithDupes(in, i = 0)
    if i == in.length():
        yield break
    ch = in[i]
    childitems = combineWithDupes(in, i +1)
    yield ch                                    // a
    for child in childitems:                    // a, aa
        yield ch + child                        // aa, aaa
    if i +1 &lt; in.length() &amp;&amp; in[i] == in[i +1]:
        yield break
    for child in childitems:                    // a, aa
        yield child                             // a, aa
&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/2813968540287373130/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2017/10/combinations-with-duplicates.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/2813968540287373130'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/2813968540287373130'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2017/10/combinations-with-duplicates.html' title='combinations with duplicates'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-3745087699264479768</id><published>2017-10-22T14:00:00.000-07:00</published><updated>2017-10-26T11:41:16.711-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>if string is a subsequence of another</title><content type='html'>&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
bool (sub, s):
    if s == null || sub == null:
        throw
    if sub.length() &gt; s.length():
        return false
    for i = 0, j = 0; i &lt; s.length() &amp;&amp; j &lt; sub.length(); i++:
        if s[i] == sub[j]:
            j++
    return j == sub.length()
&lt;/pre&gt;
Follow-up: There are multiple strings to check. &lt;br/&gt;
&lt;br/&gt;
Keep a ch-&gt;indexes map for s. For each ch of sub, get the first index as i which is greater than previ (i of previous ch).
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
(subs, s):
    subCount = 0
    cindexMap = createIndexMap(s)
    for sub in subs:
        if isSubsequence(sub, cindexMap);   
            subCount++
    
bool isSubsequence(sub, cindexMap):
    previ = -1
    for c in sub:
        if !cindexMap.hasKey(c):
            return false
        indexs = cindexMap[c]
        i = -1
        // could use binary search
        for index in indexs:
            if index &gt; previ:
                i = index
                break
        if i == -1:
            return false
        previ = i
    return true
    
map createIndexMap(s):
    // c-&gt;indexs map, indexs is list
    cindexMap = new
    for i = 0, i &lt; t.length(), i++:
        c = t[i]
        if !cindexMap.hasKey(c):
            indexs = new list()
            cindexMap[c] = indexs
        else:
            indexs = cindexMap[c]
        indexs.add(i)
    return cindexMap
&lt;/pre&gt;
It&#39;s easier to check by generating all sub-sequences using combinations (uses O(2^n) space).
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
(subs, s):
    subCount = 0
    combinations = combine(s)
    for sub in combinations:
        subSet.add(sub)
    for sub in subs:
        if subSet.has(sub):
            subCount++

// for abc, gives
// a
// ab
// abc
// ac
// b
// bc
// c
[] combine(s):
&lt;/pre&gt;
[Hat tip to &lt;a href=&quot;https://discuss.leetcode.com/topic/67167/java-code-for-the-follow-up-question&quot;&gt;LeCo&lt;/a&gt;]</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/3745087699264479768/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2017/10/if-string-is-subsequence-of-another.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/3745087699264479768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/3745087699264479768'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2017/10/if-string-is-subsequence-of-another.html' title='if string is a subsequence of another'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-9062979428886954305</id><published>2017-10-19T01:00:00.000-07:00</published><updated>2019-10-27T23:57:29.624-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><category scheme="http://www.blogger.com/atom/ns#" term="data structures"/><title type='text'>if binary tree is full, perfect, complete</title><content type='html'>full: each node has 0 or 2 child nodes.
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
// full
    x
 x     x
      x x

// not full
    x
 x     x
x     x x

bool isfull(n):
    if n == null:
        return true
    if n.left == null != n.right == null: // same as ^
        return false
    return (n.left) &amp;&amp; (n.right)
&lt;/pre&gt;
perfect: tree has 2^depth -1 nodes (i.e. each level is full).&lt;br&gt;
tip: The depths of left and right subtrees are equal at all levels.
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
// perfect
    x
 x     x
x x   x x

bool isPerfect(n):
    return depthPerfect(n) != null

int? depthPerfect(n):
    if n == null:
        return 0
    ldepth = (n.left)
    if rdepth == null:
        return null
    rdepth = (n.right)
    if rdepth == null:
        return null
    if ldepth != rdepth:
        return null
    return ldepth +1 // or rdepth +1
&lt;/pre&gt;
complete: nodes at last level are filled from left.&lt;br&gt;
tip: After encountering a null child, no nodes in queue should have any children.
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
// complete
    x
 x     x
x x   x

// not complete
    x
 x     6
x x     7

    4
 2     6
1     5

// bfs
bool isComplete(node):
    if node == null:
        return true
    q = new
    q.enqueue(node)
    ended = false
    while !q.isEmpty():
        n = q.dequeue()
        if ended &amp;&amp; n.left != null:
            return false
        if n.left != null:
            q.enqueue(n.left)
        else:
            ended = true
        if ended &amp;&amp; n.right != null:
            return false
        if n.right != null:
            q.enqueue(n.right)
        else:
            ended = true
    return true

// bfs
bool isComplete(node):
    if node == null:
        return true
    q = new
    q.enqueue(node)
    ended = false
    while !q.isEmpty():
        n = q.dequeue()
        if ended &amp;&amp; (n.left != null || n.right != null):
            return false        
        if n.left == null &amp;&amp; n.right != null:
            return false
        ended = n.left == null || n.right == null
        if n.left != null:
            q.enqueue(n.left)
        if n.right != null:
            q.enqueue(n.right)
    return true

// dfs
bool isComplete(n):
    return (n, count(n) -1)

bool isComplete(n, maxi, i = 0):
    if n == null:
        return true
    if i &gt; maxi:
        return false
    // faster to check right subtree first as
    // right subtree returns false if not complete
    return isComplete(n.right, maxi, i*2 +2)
        &amp;&amp; isComplete(n.left, maxi, i*2 +1)

int count(n):
    if n == null:
        return 0
    return 1 + count(n.left) + count(n.right)

// dfs
bool isComplete(n):
    isComplete(n, count: {value: 0}, maxi: {value: 0}, i: 0)
    return count.value &lt; i.value +1

isComplete(n, count, maxi, i):
    if n == null:
        return
    count.value++
    maxi.value = max(maxi.value, i)
    (n.left, count, maxi, i*2 +1)
    (n.right, count, maxi, i*2 +2)

// bfs
bool isComplete(node):
    if node == null:
        return true
    q = new
    q.enqueue((node, iexp: 0))
    i = 0
    while !q.isEmpty():
        n, iexp = q.dequeue()
        if iexp &gt; i:
            return false
        i++
        if n.left != null:
            q.enqueue((n.left, iexp*2 +1))
        if n.right != null:
            q.enqueue((n.right, iexp*2 +2))
    return true
&lt;/pre&gt;
[Hat tip to ctci]</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/9062979428886954305/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2017/10/if-binary-tree-is-full-perfect-complete.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/9062979428886954305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/9062979428886954305'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2017/10/if-binary-tree-is-full-perfect-complete.html' title='if binary tree is full, perfect, complete'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-1067289076298402943</id><published>2017-10-13T12:00:00.000-07:00</published><updated>2017-10-15T22:45:57.290-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>reverse a stack with recursion</title><content type='html'>&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
// time: O(n^2), space: O(n)
(stack):
    for i = stack.size() -1, i &gt; 0, i--:
        top = stack.pop()
        (stack, i, top)

// time: O(n), space: O(n)
(stack, i, top):
    if i == 0:
        stack.push(top)
        return
    // no need to check if stack empty
    temp = stack.pop()
    (stack, i -1, top)
    stack.push(temp)
&lt;/pre&gt;

OR

&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
// time: O(n^2), space: O(n)
(stack):
    if stack.isEmpty():
        return
    temp = stack.pop()
    (stack)
    insertAtBottom(stack, temp)

// time: O(n), space: O(n)
insertAtBottom(stack, x):
    if stack.isEmpty():
        stack.push(x)
        return
    temp = stack.pop()
    insertAtBottom(stack, x)
    stack.push(temp)
&lt;/pre&gt;

[Hat tip to GfG]</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/1067289076298402943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2017/10/reverse-stack-with-recursion.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/1067289076298402943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/1067289076298402943'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2017/10/reverse-stack-with-recursion.html' title='reverse a stack with recursion'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-4704470821730442728</id><published>2017-10-12T22:00:00.000-07:00</published><updated>2017-10-12T22:00:00.168-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><category scheme="http://www.blogger.com/atom/ns#" term="data structures"/><title type='text'>queue with 1 stack</title><content type='html'>Using recursion and backtracking, i.e. using the method call stack as the &quot;other&quot; stack to hold on to the elements.
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
// O(n)
enqueue(x):
    if stack.isEmpty():
        stack.push(x)
        return
    temp = stack.pop()
    enqueue(x)
    stack.push(temp)

// O(1)
x dequeue():
    return stack.pop()
&lt;/pre&gt;

&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
// O(1)
enqueue(x):
    stack.push(x)

// O(n)
x dequeue():
    temp = stack.pop()
    if stack.isEmpty():
        x = temp
    else:
        x = dequeue()
        stack.push(temp)
    return x
&lt;/pre&gt;

[Hat tip to &lt;a href=&quot;https://stackoverflow.com/a/77010/58678&quot;&gt;SO&lt;/a&gt;]</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/4704470821730442728/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2017/10/queue-with-1-stack.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/4704470821730442728'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/4704470821730442728'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2017/10/queue-with-1-stack.html' title='queue with 1 stack'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-5578712798929552303</id><published>2017-10-06T20:00:00.000-07:00</published><updated>2018-02-22T17:18:20.716-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>flatten binary tree to right</title><content type='html'>Flatten to node&#39;s right pointers only.
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
    1
   / \
  2   5
 / \   \
3   4   6


 1
  \
   2
    \
     3
      \
       4
        \
         5
          \
           6
&lt;/pre&gt;

&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
(n):
    if n == null:
        return
    if n.left != null:
        lsubtree = n.left
        rsubtree = n.right
        n.left = n.right = null
        n.right = lsubtree
        // rightmost of left subtree
        rmost = lsubtree
        while rmost.right != null:
            rmost = rmost.right
        rmost.right = rsubtree
    (n.right)
&lt;/pre&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
(n):
    while n != null:
        if n.left != null:
            lsubtree = n.left
            rsubtree = n.right
            n.left = n.right = null
            n.right = lsubtree
            rmost = lsubtree
            while rmost != null:
                rmost = rmost.right
            rmost.right = rsubtree
        n = n.right
&lt;/pre&gt;

[Hat tip to LeCo]</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/5578712798929552303/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2017/10/flatten-binary-tree-to-right.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/5578712798929552303'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/5578712798929552303'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2017/10/flatten-binary-tree-to-right.html' title='flatten binary tree to right'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-10096563.post-3804448546965938166</id><published>2017-10-06T16:00:00.000-07:00</published><updated>2019-01-28T00:14:24.067-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="algorithms"/><title type='text'>lfu cache of n items</title><content type='html'>lfu cache with O(logn) get, add, delete.&lt;br /&gt;
&lt;pre style=&quot;background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); font-family: &#39;Andale Mono&#39;, &#39;Lucida Console&#39;, Monaco, fixed, monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 546px;&quot;&gt;
lfuCache:
    map
    minheap
    n
    
    ctor(n):
        if n &lt; 0:
            throw
        n = n
        map = new map(capacity: n)
        minheap = new minheap(n, item =&gt; item.frequency)
    
    value get(key):
        if key == null: throw
        // do not throw if key no exists
        if !has(key):
            return null // default(value)
        item = map[key]
        item.frequency++ // possible overflow
        minheap.heapify()
        return item.value
    
    add(key, value):
        if key == null: throw
        if has(key):
            item = map[key]
            item.value = value
            item.frequency = 0
            minheap.heapify()
            return
        item = {key, value, frequency: 0} // deleted item have -1 frequency
        if isfull():
            lfuitem = minheap.displace(item)
        else:
            minheap.push(item)
        map[key] = item
    
    bool delete(key):
        if key == null: throw
        // do not throw if key no exists
        if !has(key):
            return false
        item = map[key]
        item.frequency = -1 // new items have 0 frequency
        minheap.heapify()
        minheap.pop()
        map.removeKey(k)
        return true
    
    bool has(key):
        if key == null: throw
        return map.haskey(key)
    
    int count():
        return minheap.count()
    int isfull():
        return count() == n

// heapify x by keySelector
minheap:
    ctor(n, keySelector):
        n = n
        keySelector = keySelector
    push(x):
    x pop():
    // uses siftdown
    heapify():
    // returns top, replacing with x, heapify
    x displace(x):
    int count():

item:
    value
    frequency // unsigned to reduce overflow chance
&lt;/pre&gt;
</content><link rel='replies' type='application/atom+xml' href='http://rmandvikar.blogspot.com/feeds/3804448546965938166/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://rmandvikar.blogspot.com/2017/10/lfu-cache-of-n-items.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/3804448546965938166'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/10096563/posts/default/3804448546965938166'/><link rel='alternate' type='text/html' href='http://rmandvikar.blogspot.com/2017/10/lfu-cache-of-n-items.html' title='lfu cache of n items'/><author><name>RM</name><uri>http://www.blogger.com/profile/09878938744633565042</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>