What you could do (in close to O(n) time, if I'm not mistaken) is, parameterizing it with "limit", prepare / pre-compute an epsilon-free context-free grammar such as (for limit = 3),
Upto3 -> LimitOnes | LimitZeros
LimitOnes -> Zeros Ones LimitOnes | Zeros Ones | Zeros
LimitZeros -> Ones Zeros LimitZeros | Ones Zeros | Ones
Zeros -> Zero | Zero Zero | Zero Zero Zero
Ones -> One | One One | One One One
Zero -> 0
One -> 1
(please note: I don't claim it's the correct or simplest grammar you will want you use, but you can always fiddle / experiment with your own using the nifty Grammophone tool, by Michael Daines)
where "Upto3" is the grammar's axiom / start symbol.
(The only two rules depending on N being Zeros -> ... and Ones -> ...)
Then, using such a pre-computed grammar (that you'll use for generation purposes instead of parsing), you can write a simple recursive function, which, starting from the start symbol, randomly picks one of the alternatives of the rules and applies it, by string concatenation, on an accumulator that it passes to itself (and that you'll have passed as the empty string for the top level call).
At each recursive call, it is trivial to decide (depending on N and the last known length of the accumulator) which alternative branch of the rules (aka, productions) -- LimitOnes, LimitZeros, Ones, or Zeros -- it is meaningful to follow (to not exceed N).
Eg,
N = 10, limit = 3:
start with Upto3 : accumulator = ""
from "Upto3", randomly pick "LimitZeros"
from "LimitZeros", apply "Ones", "Zeros" in "Ones Zeros LimitZeros" : accumulator = "100"
from "LimitZeros", apply "Ones", "Zeros" in "Ones Zeros LimitZeros" : accumulator = "100110"
etc, etc.
I let you figure out the implementation details.
'Hope this helps,