[SPARK-3250] Implement Gap Sampling optimization for random sampling

More efficient sampling, based on Gap Sampling optimization:
http://erikerlandson.github.io/blog/2014/09/11/faster-random-samples-with-gap-sampling/

i think this is easier to read if you do
```scala
if (ub <= lb) {
  if (complement) items else Iterator.empty
} else {
  if (complement) {
    items.filter { item =>
      val x = rng.nextDouble()
      (x < lb) || (x >= ub)
    }
  } else {
    items.filter { _ =>
      val x = rng.nextDouble()
      (x >= lb) && (x < ub)
    }
  }
}
```