Problem
A robot is located at the top-left corner of a NXN grid. The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid. How many possible unique paths are there?Approach
UniquePaths(row, column) = 0 if row > N or column > N
1 if row ==N and column == N
UniquePaths(row+1, column) + UniquePaths(row, column+1)
i.e, the recursive method has optimal substructure and overlapping sub problems. So, the problem can be solved using Dynamic Programming.
Code Snippet
- private int GetNumberOfUniquePaths(int row, int column, int N)
- {
- if ((row == N) && (column == N))
- {
- return 1;
- }
- if ((row > N) || (column > N))
- {
- return 0;
- }
- int uniquePathsByMovingDown = this.GetNumberOfUniquePaths(row + 1, column, N);
- int uniquePathsByMovingRight = this.GetNumberOfUniquePaths(row, column + 1, N);
- return uniquePathsByMovingDown + uniquePathsByMovingRight;
- }
- int GetNumberOfUniquePaths(int N)
- {
- int r = this.GetNumberOfUniquePaths(1, 1, N);
- return r;
- }
DP - Memoization (Top-Down - Lazy)
Code Snippet
- int GetUniquePaths_DP_Memoization_Lazy(int N)
- {
- int?[][] DP_Memoization_Lazy_Cache = new int?[N + 1][];
- for(int i =0;i<=N;i++)
- {
- DP_Memoization_Lazy_Cache[i] = new int?[N + 1];
- for(int j=0;j<=N;j++)
- {
- DP_Memoization_Lazy_Cache[i][j] = null;
- }
- }
- this.GetUniquePaths_DP_Memoization_Lazy(DP_Memoization_Lazy_Cache, row: 1, column: 1);
- return DP_Memoization_Lazy_Cache[1][1].Value;
- }
- private int GetUniquePaths_DP_Memoization_Lazy(int?[][] DP_Memoization_Lazy_Cache, int row,
- int column)
- {
- int N = DP_Memoization_Lazy_Cache.Length - 1;
- if (row > N)
- {
- return 0;
- }
- if (column > N)
- {
- return 0;
- }
- if(DP_Memoization_Lazy_Cache[row][column] != null)
- {
- return DP_Memoization_Lazy_Cache[row][column].Value;
- }
- if((row == N) && (column == N))
- {
- DP_Memoization_Lazy_Cache[N][N] = 1;
- return 1;
- }
- int pathsWhenMovedDown = this.GetUniquePaths_DP_Memoization_Lazy(DP_Memoization_Lazy_Cache,
- row + 1, column);
- int pathsWhenMovedRight = this.GetUniquePaths_DP_Memoization_Lazy(DP_Memoization_Lazy_Cache,
- row, column + 1);
- DP_Memoization_Lazy_Cache[row][column] = pathsWhenMovedDown + pathsWhenMovedRight;
- return DP_Memoization_Lazy_Cache[row][column].Value;
- }
Getting Paths
Code Snippet
- Tuple<int, int>[][] GetUniquePaths(int N)
- {
- var r = this.GetUniquePaths(1, 1, N);
- return r;
- }
- private Tuple<int, int>[][] GetUniquePaths(int row, int column, int N)
- {
- if ((row == N) && (column == N))
- {
- var r = new Tuple<int, int>[1][];
- r[0] = new Tuple<int, int>[] { new Tuple<int,int>(row, column) };
- return r;
- }
- if ((row > N) || (column > N))
- {
- return new Tuple<int, int>[0][];
- }
- var uniquePathsByMovingDown = this.GetUniquePaths(row + 1, column, N);
- var uniquePathsByMovingRight = this.GetUniquePaths(row, column + 1, N);
- List<Tuple<int, int>[]> paths = this.MergePaths(uniquePathsByMovingDown,
- row, column).ToList();
- paths.AddRange(this.MergePaths(uniquePathsByMovingRight, row, column));
- return paths.ToArray();
- }
- private Tuple<int, int>[][] MergePaths(Tuple<int, int>[][] paths,
- int row, int column)
- {
- Tuple<int, int>[][] mergedPaths = new Tuple<int, int>[paths.Length][];
- if (paths.Length > 0)
- {
- Assert.IsTrue(paths.All(p => p.Length > 0));
- for (int i = 0; i < paths.Length; i++)
- {
- List<Tuple<int, int>> mergedPath = new List<Tuple<int, int>>();
- mergedPath.Add(new Tuple<int, int>(row, column));
- mergedPath.AddRange(paths[i]);
- mergedPaths[i] = mergedPath.ToArray();
- }
- }
- return mergedPaths;
- }
DP - Bottom-Up
Code Snippet
- int DP_BottomUp_GetNumberOfUniquePaths(int N)
- {
- int[][] DP_BottomUp_Tabular_Eager_Cache = new int[N + 1][];
- for (int row = 0; row <= N; row++)
- {
- DP_BottomUp_Tabular_Eager_Cache[row] = new int[N + 1];
- for (int column = 0; column <= N; column++)
- {
- if ((row == N)
- || (column == N))
- {
- DP_BottomUp_Tabular_Eager_Cache[row][column] = 1;
- }
- }
- }
- for (int row = N - 1; row >= 1;row--)
- {
- for (int column = N - 1; column >= 1; column--)
- {
- DP_BottomUp_Tabular_Eager_Cache[row][column] =
- DP_BottomUp_Tabular_Eager_Cache[row + 1][column]
- + DP_BottomUp_Tabular_Eager_Cache[row][column + 1];
- }
- }
- return DP_BottomUp_Tabular_Eager_Cache[1][1];
- }
Unit Tests
Code Snippet
- [TestMethod]
- [TestCategory(Constants.DynamicProgramming)]
- public void RobotInGridTests()
- {
- int p = this.DP_BottomUp_GetNumberOfUniquePaths(3);
- Assert.AreEqual(p, 6);
- p = GetNumberOfUniquePaths(3);
- Assert.AreEqual(p, 6);
- int p1 = this.GetUniquePaths_DP_Memoization_Lazy(3);
- Assert.AreEqual(p, p1);
- var p2 = this.GetUniquePaths(3);
- Assert.AreEqual(p1, p2.Length);
- foreach (var path in p2)
- {
- Debug.WriteLine("===================================================================");
- foreach (Tuple<int, int> t in path)
- {
- Debug.Write(string.Format("({0}, {1}), ", t.Item1, t.Item2));
- }
- }
- p = this.DP_BottomUp_GetNumberOfUniquePaths(4);
- Assert.AreEqual(p, 20);
- p = GetNumberOfUniquePaths(4);
- Assert.AreEqual(p, 20);
- p1 = this.GetUniquePaths_DP_Memoization_Lazy(4);
- Assert.AreEqual(p, p1);
- p2 = this.GetUniquePaths(4);
- Assert.AreEqual(p1, p2.Length);
- foreach (var path in p2)
- {
- Debug.WriteLine("===================================================================");
- foreach (Tuple<int, int> t in path)
- {
- Debug.Write(string.Format("({0}, {1}), ", t.Item1, t.Item2));
- }
- }
- }
Finding the number of paths mathematically
Say, if the grid is 4X4 => i.e, the number of unique paths is nothing but all possible permutations of RRRDDD where R represents right and D represents Down. For details, please see the attached image:
No comments:
Post a Comment