1) Your code doesn't handle number=0 properly anyway (it will throw on int squareWidth = rectangleWidth / nSquaresInColumn;) so I would start your first loops (i,j iterators) from 1 since 0 rows/columns won't fit anyway.
2) You do not actually need j loop. Instead of:
for (int i = 0; i <= numberOfSquares; i++) { for (int j = 0; j <= numberOfSquares; j++) { if (i * j == numberOfSquares) { ... } } }
It can simplified to (and taking into account my #1):
for (int i = 1; i <= numberOfSquares; i++) { int j = numberOfSquares / i; if (i * j == numberOfSquares) { ... } }
3) You don't need to iterate up to numberOfSquares here: for (int i = 1; i <= numberOfSquares; i++). Since i=2,j=6 is the same as i=6,j=2 and you're looking only for first one you can iterate up to root square of numberOfSquares:
int maxI = (int)Math.Sqrt(numberOfSquares); for (int i = 1; i <= maxI; i++)
4) Since you're looking for minimal i-j difference you should start iterating from closest one and stop iterating as soon as you will find matching pair. Original:
int maxI = (int)Math.Sqrt(numberOfSquares); for (int i = 1; i <= maxI; i++) { int j = numberOfSquares / i; if (i * j == numberOfSquares) { if (Math.Abs(i - j) < minDistance) { minDistance = Math.Abs(i - j); nSquaresInRow = i; nSquaresInColumn = j; } } }
Modified:
int maxI = (int)Math.Sqrt(numberOfSquares); for (int i = maxI; i >= 1; i--) // looping in reverse order { int j = numberOfSquares / i; if (i * j == numberOfSquares) { // if (Math.Abs(i - j) < minDistance) we do not need this check anymore { minDistance = Math.Abs(i - j); nSquaresInRow = i; nSquaresInColumn = j; break; } } }
5) With my #3 change you do not need Math.Abs anymore since i is always less or equal than j:
minDistance = j - i;
Now let's go to second loop:
6) int xSquareCenter = (((r + 1) * 2) - 1) * (squareWidth / 2); here double maths should be used otherwise you're loosing precision here.
7) Also this line is a little bit difficult to understand. I would introduce row and column variables to make it more clear:
int column = r % nSquaresInRow; double xSquareCenter = (column + 0.5) * squareWidth; int row = r / nSquaresInRow; double ySquareCenter = (row + 0.5) * squareHeight;
8) Last thing, I would replace both loops with Linq. Final result:
public static List<Point> getCenters(int number, double width, double height) { List<Point> points = new List<Point>(); int originalNumberOfSquares = number; int numberOfSquares = number; if (numberOfSquares % 2 == 1) { numberOfSquares++; } int rectangleWidth = Convert.ToInt32(width); int rectangleHeight = Convert.ToInt32(height); int nSquaresInRow = -1; int nSquaresInColumn = -1; int maxI = (int)Math.Sqrt(numberOfSquares); int nSquaresInRow = Enumerable.Range(1, maxI) .Reverse() .First(i => numberOfSquares % i == 0); int nSquaresInColumn = numberOfSquares / nSquaresInRow; int squareWidth = rectangleWidth / nSquaresInColumn; int squareHeight = rectangleHeight / nSquaresInRow; return Enumerable.Range(0, originalNumberOfSquares) .Select(r => new { Column = r % nSquaresInRow, Row = r / nSquaresInRow}) .Select(p => new { xSquareCenter = (p.Column + 0.5) * squareWidth, ySquareCenter = (p.Row + 0.5) * squareHeight}) .Select(p => new Point(p.xSquareCenter, p.ySquareCenter)) .ToList(); }