Generally the collisions in a hash function are, in a way, what winds up improving the running time.
This is because running time (or size, or insertion time) is generally defined in terms of worst-case input. If you use an algorithm without any randomness or hash, you need to deal with the worst case. For example, finding duplicate elements in an array has an $\Omega(n\log n)$ in the comparison model, same as sorting. But if you just hash the values, you can determine whether or not there's a duplicate in $O(n)$ time and space with a small probability of error. Determining a hash function that wouldn't collide, eliminating the possibility of error, has to take $\Omega(n\log n)$ time. (You may notice that these are, in a way, the same problem--though of course hashed values generally belong to a smaller universe and the comparison model may not be appropriate).
That said, there are some ways to take advantage of the ways hash functions collide. One is locally sensitive hash functions, in which elements with small differences (i.e. normal distance functions for points) hash to the same value. Recently I've been reading this paper(1), which I found really easy to read, and shows some good, intuitive applications for how a locally sensitive hash function can be used to solve seemingly difficult problems--in this case the nearest neighbor problem with small probability of error.
Incidentally, the space advantage of possible collisions is how bloom filters work, a data structure that allows you to store elements of a set, each in space smaller than their actual size. They are a constant factor away from optimal, and the upper and lower bounds demonstrate the tradeoff between error and space.
(1) Neylon, T. A locally sensitive hash for real vectors. SODA2010.