[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/

Is this going to be inefficient to keep accessing the class and its name on every invocation?
And rather than match on class names, can you just match an instance of `Array` or `ArrayBuffer`? I may be missing a reason you can't do that in Scala here. I understand you're avoiding calling `drop` for other types.