0% found this document useful (0 votes)
87 views47 pages

10 Classic Coding Challenges Book

Uploaded by

Duc Le Van
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
87 views47 pages

10 Classic Coding Challenges Book

Uploaded by

Duc Le Van
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 47

10 Classic Coding

Challenges
Essential Problem Solving Skills, Fundamental Algorithms,
Basic Data Structures and C++ Programming Language

Nhut Nguyen, Ph.D.


10 Classic Coding Challenges
Essential Problem Solving Skills, Fundamental Algorithms, Basic Data
Structures and C++ Programming Language

Nhut Nguyen, Ph.D.

July 2022
ii
Contents

Maximum Depth of Binary Tree 1

Container With Most Water 5

Single Number 9

Majority Element 13

Excel Sheet Column Number 17

Valid Parentheses 21

Product of Array Except Self 25

Find the Duplicate Number 29

Spiral Matrix II 33

Unique Paths 37

iii
iv CONTENTS
Maximum Depth of Binary Tree

Problem statement
Given the root of a binary tree, return its maximum depth.
A binary tree’s maximum depth is the number of nodes along the longest path from
the root node down to the farthest leaf node.

Example 1

Figure 1: The binary tree in Example 1


Input: root = [3,9,20,null,null ,15,7]
Output: 3

Example 2
Input: root = [1,null ,2]
Output: 2

Constraints
• The number of nodes in the tree is in the range [0, 10^4].
• ‐100 <= Node.val <= 100.

1
2 MAXIMUM DEPTH OF BINARY TREE

Solution: Recursive
You have the following recursive relationship between the root and its children.
maxDepth(root) = max(maxDepth(root‐>left), maxDepth(root‐>right))

Code
#include <iostream >
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode( int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode( int x, TreeNode *left, TreeNode *right) : val(x), left(
left), right(right) {}
};

int maxDepth(TreeNode* root) {


if (root == nullptr) {
return 0;
}
return 1 + std::max(maxDepth(root‐>left), maxDepth(root‐>right));
}

int main() {
TreeNode fifteen(15);
TreeNode seven(7);
TreeNode twenty(20, &fifteen , &seven);
TreeNode nine(9);
TreeNode three(3, &nine, &twenty);
std::cout << maxDepth(&three) << std::endl;
TreeNode two(2);
TreeNode one(1, nullptr , &two);
std::cout << maxDepth(&one) << std::endl;
}

Output:
3
2
REFERENCES 3

Complexity
• Runtime: O(N), where N is the number of nodes.
• Extra space: O(N).

References
• https://leetcode.com/problems/maximum-depth-of-binary-tree/
• https://www.leetsolve.com/104-maximum-depth-of-binary-tree
4 MAXIMUM DEPTH OF BINARY TREE
Container With Most Water

Problem statement
You are given an integer array height of length n. There are n vertical lines drawn
such that the two endpoints of the i‐th line are (i, 0) and (i, height[i]).
Find two lines that together with the x-axis form a container, such that the container
contains the most water.
Return the maximum amount of water a container can store.
Notice that you may not slant the container.

Example 1

Figure 2: The container in Example 1

Input: height = [1,8,6,2,5,4,8,3,7]


Output: 49
Explanation: The above vertical lines are represented by array
[1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue
section) the container can contain is 49.

5
6 CONTAINER WITH MOST WATER

Example 2
Input: height = [1,1]
Output: 1

Constraints
• n == height.length.
• 2 <= n <= 10^5.
• 0 <= height[i] <= 10^4.

Solution 1: Bruteforce
For each line i, find the line j > i such that it gives the maximum amount of water
the container (i, j) can store.

Code
#include <iostream >
#include <vector >
using namespace std;
int maxArea(vector < int >& height) {
int maxA = 0;
for ( int i = 0; i < height.size() ‐ 1; i++) {
for ( int j = i + 1; j < height.size(); j++) {
maxA = max(maxA, min(height[i], height[j]) * (j ‐ i) );
}
}
return maxA;
}
int main() {
vector< int > height{1,8,6,2,5,4,8,3,7};
cout << maxArea(height) << endl;
height = {1,1};
cout << maxArea(height) << endl;
}

Output:
49
1
SOLUTION 2: TWO POINTERS 7

Complexity
• Runtime: O(N^2), where N = height.length.
• Extra space: O(1).

Solution 2: Two pointers


Any container has left line i and right line j satisfying 0 <= i < j < height.length.
The biggest container you want to find satisfies that condition too.
You can start from the broadest container with the left line i = 0 and the right line
j = height.length ‐ 1. Then by moving i forward and j backward, you can narrow
down the container to find which one will give the maximum amount of water it can
store.
Depending on which line is higher, you can decide which one to move next. Since you
want a bigger container, you should move the shorter line.

Example 1
For height = [1,8,6,2,5,4,8,3,7]:
• Starting with i = 0 and j = 8:
area = min(height[i], height[j]) * (j ‐ i) = min(1, 7) * (8 ‐ 0)
= 8.
maxArea = 8.

• height[i] = 1 < 7 = height[j], move i to 1:


area = min(8, 7) * (8 ‐ 1) = 49.
maxArea = 49.

• height[i] = 8 > 7 = height[j], move j to 7:


area = min(8, 3) * (7 ‐ 1) = 18.
maxArea = 49.

• So on and so on. Final maxArea = 49.

Code
#include <iostream >
#include <vector >
using namespace std;
int maxArea(vector < int >& height) {
8 CONTAINER WITH MOST WATER

int maxA = 0;
int i = 0;
int j = height.size() ‐ 1;
while (i < j) {
if (height[i] < height[j]) {
maxA = max(maxA, height[i] * (j ‐ i) );
i++;
} else {
maxA = max(maxA, height[j] * (j ‐ i) );
j‐‐;
}
}
return maxA;
}
int main() {
vector< int > height{1,8,6,2,5,4,8,3,7};
cout << maxArea(height) << endl;
height = {1,1};
cout << maxArea(height) << endl;
}

Output:
49
1

Complexity
• Runtime: O(N), where N = height.length.
• Extra space: O(1).

References
• https://leetcode.com/problems/container-with-most-water/
• https://www.leetsolve.com/11-container-with-most-water
Single Number

Problem statement
Given a non-empty array of integers nums, every element appears twice except for one.
Find that single one.

You must implement a solution with a linear runtime complexity and use only constant
extra space.

Example 1
Input: nums = [2,2,1]
Output: 1

Example 2
Input: nums = [4,1,2,1,2]
Output: 4

Example 3
Input: nums = [1]
Output: 1

Constraints
• 1 <= nums.length <= 3 * 10^4.
• ‐3 * 10^4 <= nums[i] <= 3 * 10^4.
• Each element in the array appears twice except for one element which appears
only once.

9
10 SINGLE NUMBER

Solution 1: Counting the appearances


Count how many times each element appears in the array. Then return the one ap-
pearing only once.

Code
#include <vector >
#include <iostream >
#include <unordered_map >
using namespace std;
int singleNumber(vector < int >& nums) {
unordered_map < int , int > count;
for ( int n : nums) {
count[n]++;
}
int single;
for ( auto & pair : count) {
if (pair.second == 1) {
single = pair.first;
break ;
}
}
return single;
}
int main() {
vector< int > nums{2,2,1};
cout << singleNumber(nums) << endl;
nums = {4,1,2,1,2};
cout << singleNumber(nums) << endl;
nums = {1};
cout << singleNumber(nums) << endl;
}

Output:
1
4
1

Complexity
• Runtime: O(N), where N = nums.length.
• Extra space: O(N) (not constant, need another solution).
SOLUTION 2: BITWISE EXCLUSIVE OR 11

Solution 2: Bitwise exclusive OR


You can also use the bitwise XOR operator to cancel out the duplicated elements in
the array. The remain element is the single one.
a XOR a = 0.
a XOR 0 = a.

Code
#include <vector >
#include <iostream >
using namespace std;
int singleNumber(vector < int >& nums) {
int single = 0;
for ( int n : nums) {
single ^= n;
}
return single;
}
int main() {
vector< int > nums{2,2,1};
cout << singleNumber(nums) << endl;
nums = {4,1,2,1,2};
cout << singleNumber(nums) << endl;
nums = {1};
cout << singleNumber(nums) << endl;
}

Output:
1
4
1

Complexity
• Runtime: O(N), where N = nums.length.
• Extra space: O(1).

References
• https://leetcode.com/problems/single-number/
• https://www.leetsolve.com/136-single-number
12 SINGLE NUMBER
Majority Element

Problem statement
Given an array nums of size n, return the majority element.
The majority element is the element that appears more than n/2 times. You may
assume that the majority element always exists in the array.

Example 1
Input: nums = [3,2,3]
Output: 3

Example 2
Input: nums = [2,2,1,1,1,2,2]
Output: 2

Constraints
• n == nums.length.
• 1 <= n <= 5 * 10^4.
• ‐2^31 <= nums[i] <= 2^31 ‐ 1.

Follow-up:
Could you solve the problem in linear time and in O(1) space?

Solution 1: Counting the frequency


Code

13
14 MAJORITY ELEMENT

#include <vector >


#include <iostream >
#include <unordered_map >
using namespace std;
int majorityElement(vector < int >& nums) {
unordered_map < int , int > freq;
const int HALF = nums.size() / 2;
for ( int a : nums) {
freq[a]++;
if (freq[a] > HALF) {
return a;
}
}
return nums[0];
}
int main() {
vector< int > nums{3,2,3};
cout << majorityElement(nums) << endl;
nums = {2,2,1,1,1,2,2};
cout << majorityElement(nums) << endl;
}

Output:
3
2

Complexity
• Runtime: O(n), where n = nums.length.
• Extra space: O(n).

Solution 2: Sorting and picking the middle element


Code
#include <vector >
#include <iostream >
#include <algorithm >
using namespace std;
int majorityElement(vector < int >& nums) {
sort(nums.begin(), nums.end());
return nums[nums.size()/2];
REFERENCES 15

}
int main() {
vector< int > nums{3,2,3};
cout << majorityElement(nums) << endl;
nums = {2,2,1,1,1,2,2};
cout << majorityElement(nums) << endl;
}

Output:
3
2

Complexity
• Runtime: O(nlogn), where n = nums.length.
• Extra space: O(1).

References
• https://leetcode.com/problems/majority-element/
• https://www.leetsolve.com/169-majority-element
16 MAJORITY ELEMENT
Excel Sheet Column Number

Problem statement
Given a string columnTitle that represents the column title as appears in an Excel
sheet, return its corresponding column number.
For example:
A ‐> 1
B ‐> 2
C ‐> 3
...
Z ‐> 26
AA ‐> 27
AB ‐> 28
...

Example 1
Input: columnTitle = "A"
Output: 1

Example 2
Input: columnTitle = "AB"
Output: 28

Example 3
Input: columnTitle = "ZY"
Output: 701

17
18 EXCEL SHEET COLUMN NUMBER

Constraints
• 1 <= columnTitle.length <= 7.
• columnTitle consists only of uppercase English letters.
• columnTitle is in the range ["A", "FXSHRXW"].

Solution: Finding The Pattern


Let us write down some other columnTitle strings and its value.
"A" = 1
"Z" = 26
"AA" = 27
"AZ" = 52
"ZZ" = 702
"AAA" = 703

Then try to find the pattern


"A" = 1 = 1
"Z" = 26 = 26
"AA" = 27 = 26 + 1
"AZ" = 52 = 26 + 26
"ZZ" = 702 = 26*26 + 26
"AAA" = 703 = 26*26 + 26 + 1

If you map 'A' = 1, ..., 'Z' = 26, the values can be rewritten as
"A" = 1 = 'A'
"Z" = 26 = 'Z'
"AA" = 27 = 26*'A' + 'A'
"AZ" = 52 = 26*'A' + 'Z'
"ZZ" = 702 = 26*'Z' + 'Z'
"AAA" = 703 = 26*26*'A' + 26*'A' + 'A'

In general the formula for a string columnTitle = abcd is


abcd = 26^3*a + 26^2*b + 26*c + d,

where a, b, c, d are some uppercase English letters A, ..., Z.


Longer columnTitles will have bigger leading exponents of 26.

Code
SOLUTION: FINDING THE PATTERN 19

#include <iostream >


using namespace std;
int titleToNumber(string columnTitle) {
int column = 0;
for ( char c : columnTitle) {
// The ASCII value of 'A' is 65.
column = 26*column + (c ‐ 64);
}
return column;
}
int main() {
cout << titleToNumber("A") << endl;
cout << titleToNumber("AB") << endl;
cout << titleToNumber("ZY") << endl;
}

Output:
1
28
701

Complexity
• Runtime: O(N), where N = columnTitle.length.
• Extra space: O(1).

Implementation notes
1. There are many ways to compute the series
26^3*a + 26^2*b + 26*c + d.

If you write it as
26*(26*(26*(0 + a) + b) + c) + d,

you get the loop in the code above.


2. To map 'A' = 1, ..., 'Z' = 26, you can use their ASCII values ('A' = 65,
..., 'Z' = 90) minus 64.

3. The parentheses around (c ‐ 64) is needed. Otherwise the value of columnTitle


= "FXSHRXW" makes 26*column + c exceed the limit of int before it substracts
64.
20 EXCEL SHEET COLUMN NUMBER

References
• https://leetcode.com/problems/excel-sheet-column-number/
• https://www.leetsolve.com/171-excel-sheet-column-number
Valid Parentheses

Problem statement
Given a string s containing just the characters '(', ')', '{', '}', '[' and ']', deter-
mine if the input string is valid.

An input string is valid if:

1. Open brackets must be closed by the same type of brackets.


2. Open brackets must be closed in the correct order.

Example 1
Input: s = "()"
Output: true

Example 2
Input: s = "()[]{}"
Output: true

Example 3
Input: s = "(]"
Output: false

Constraints
• 1 <= s.length <= 10^4.
• s consists of parentheses only '()[]{}'.

21
22 VALID PARENTHESES

Solution: Using a stack


For each character c of s:
1. If it is an open parenthesis ('(', '{', or '['), push it into the stack.
2. If it is a closed parenthesis (')', '}', or ']') but its previous character is not
the corresponding open one, return false. End.
3. Otherwise (i.e. match open-closed), erase the pair.
4. Continue the process until all characters of s are visited.
5. Return true if the stack is empty, i.e. all valid pairs are erased.

Code
#include <iostream >
#include <stack>
using namespace std;
bool isValid(string s) {
stack< char > stk;
for ( char c : s) {
if (c == '(' || c == '[' || c == '{') {
stk.push(c);
} else if (stk.empty()) {
return false ;
} else if (c == ')' && stk.top() != '(' ||
c == ']' && stk.top() != '[' ||
c == '}' && stk.top() != '{') {
return false ;
} else {
stk.pop();
}
}
return stk.empty();
}
int main() {
cout << isValid("()") << endl;
cout << isValid("(){}[]") << endl;
cout << isValid("(]") << endl;
cout << isValid("([)]") << endl;
}

Output:
1
1
0
REFERENCES 23

Complexity:
• Runtime: O(N), where N = s.length.
• Extra space: O(N/2).

References
• https://leetcode.com/problems/valid-parentheses/
• https://www.leetsolve.com/20-valid-parentheses
24 VALID PARENTHESES
Product of Array Except Self

Problem statement
Given an integer array nums, return an array answer such that answer[i] is equal to
the product of all the elements of nums except nums[i].
The product of any prefix or suffix of nums is guaranteed to fit in a 32-bit integer.
You must write an algorithm that runs in O(n) time and without using the division
operation.

Example 1
Input: nums = [1,2,3,4]
Output: [24,12,8,6]

Example 2
Input: nums = [‐1,1,0,‐3,3]
Output: [0,0,9,0,0]

Constraints
• 2 <= nums.length <= 10^5.
• ‐30 <= nums[i] <= 30.
• The product of any prefix or suffix of nums is guaranteed to fit in a 32-bit integer.
Follow up: Can you solve the problem in O(1) extra space complexity? (The output
array does not count as extra space for space complexity analysis.)

Solution 1: Compute the prefix and suffix products


To avoid division operation, you can compute the prefix product and the suffix one of
nums[i].

25
26 PRODUCT OF ARRAY EXCEPT SELF

Code
#include <vector >
#include <iostream >
using namespace std;
vector< int > productExceptSelf(vector < int >& nums) {
const int n = nums.size();
vector< int > prefix(n);
prefix[0] = 1;
for ( int i = 1; i < n; i++) {
prefix[i] = prefix[i ‐ 1] * nums[i ‐ 1];
}
vector< int > suffix(n);
suffix[n ‐ 1] = 1;
for ( int i = n ‐ 2; i >= 0; i‐‐) {
suffix[i] = suffix[i + 1] * nums[i + 1];
}
vector< int > answer(n);
for ( int i = 0; i < n; i++) {
answer[i] = prefix[i] * suffix[i];
}
return answer;
}
void print(vector< int >& nums) {
for ( auto & v : nums) {
cout << v << " ";
}
cout << endl;
}
int main() {
vector< int > nums = {1, 2, 3, 4};
auto answer = productExceptSelf(nums);
print(answer);
nums = {‐1, 1, 0, ‐3, 3};
answer = productExceptSelf(nums);
print(answer);
}

Output:
24 12 8 6
0 0 9 0 0
SOLUTION 2: USE DIRECTLY VECTOR ANSWER TO STORE THE PREFIX PRODUCT27

Complexity
• Runtime: O(n), where n = nums.length.
• Extra space: O(2n).

Solution 2: Use directly vector answer to store the


prefix product
In the solution above you can use directly vector answer for prefix and merge the last
two loops into one.

Code
#include <vector >
#include <iostream >
using namespace std;
vector< int > productExceptSelf(vector < int >& nums) {
const int n = nums.size();
vector< int > answer(n);
answer[0] = 1;
for ( int i = 1; i < n; i++) {
answer[i] = answer[i ‐ 1] * nums[i ‐ 1];
}
int suffix = 1;
for ( int i = n ‐ 2; i >= 0; i‐‐) {
suffix *= nums[i + 1];
answer[i] *= suffix;
}
return answer;
}
void print(vector< int >& nums) {
for ( auto & v : nums) {
cout << v << " ";
}
cout << endl;
}
int main() {
vector< int > nums = {1, 2, 3, 4};
auto answer = productExceptSelf(nums);
print(answer);
nums = {‐1, 1, 0, ‐3, 3};
answer = productExceptSelf(nums);
28 PRODUCT OF ARRAY EXCEPT SELF

print(answer);
}

Output:
24 12 8 6
0 0 9 0 0

Complexity
• Runtime: O(n), where n = nums.length.
• Extra space: O(1).

References
• https://leetcode.com/problems/product-of-array-except-self/
• https://www.leetsolve.com/238-product-of-array-except-self
Find the Duplicate Number

Problem statement
Given an array of integers nums containing n + 1 integers where each integer is in the
range [1, n] inclusive.
There is only one repeated number in nums, return this repeated number.
You must solve the problem without modifying the array nums and uses only constant
extra space.

Example 1
Input: nums = [1,3,4,2,2]
Output: 2

Example 2
Input: nums = [3,1,3,4,2]
Output: 3

Constraints
• 1 <= n <= 10^5.
• nums.length == n + 1.
• 1 <= nums[i] <= n.
• All the integers in nums appear only once except for precisely one integer which
appears two or more times.
Follow up:
• How can we prove that at least one duplicate number must exist in nums?
• Can you solve the problem in linear runtime complexity?

29
30 FIND THE DUPLICATE NUMBER

Solution 1: Sorting
#include <vector >
#include <iostream >
#include <algorithm >
using namespace std;
int findDuplicate(vector < int >& nums) {
sort(nums.begin(), nums.end());
for ( int i = 0; i < nums.size() ‐ 1; i++) {
if (nums[i] == nums[i + 1]) {
return nums[i];
}
}
return 0;
}
int main() {
vector< int > nums{1,3,4,2,2};
cout << findDuplicate(nums) << endl;
nums = {3,1,3,4,2};
cout << findDuplicate(nums) << endl;
}

Output:
2
3

Complexity
• Runtime: O(NlogN), where N = nums.length.
• Extra space: O(1).

Follow up
How can we prove that at least one duplicate number must
exist in nums?
Due to Pigeonhole principle1 :
Here there are n + 1 pigeons in n holes. The pigeonhole principle says that at least
one hole has more than one pigeon.
1
https://en.wikipedia.org/wiki/Pigeonhole_principle
SOLUTION 2: MARKING THE VISITED NUMBERS 31

Can you solve the problem in linear runtime complexity?


Here are a few solutions.

Solution 2: Marking the visited numbers


Code
#include <vector >
#include <iostream >
using namespace std;
int findDuplicate(vector < int >& nums) {
vector< bool > visited(nums.size());
for ( int a : nums) {
if (visited[a]) {
return a;
}
visited[a] = true ;
}
return 0;
}
int main() {
vector< int > nums{1,3,4,2,2};
cout << findDuplicate(nums) << endl;
nums = {3,1,3,4,2};
cout << findDuplicate(nums) << endl;
}

Output:
2
3

Complexity
• Runtime: O(N), where N = nums.length.
• Extra space: O(logN). std::vector<bool>2 is optimized for space-efficient.

Solution 3: Marking with std::bitset


Since n <= 10^5, you can use this size for a std::bitset3 to do the marking.
2
https://en.cppreference.com/w/cpp/container/vector_bool
3
https://en.cppreference.com/w/cpp/utility/bitset
32 FIND THE DUPLICATE NUMBER

Code
#include <vector >
#include <iostream >
#include <bitset >
using namespace std;
int findDuplicate(vector < int >& nums) {
bitset <100001> visited;
for ( int a : nums) {
if (visited[a]) {
return a;
}
visited[a] = 1;
}
return 0;
}
int main() {
vector< int > nums{1,3,4,2,2};
cout << findDuplicate(nums) << endl;
nums = {3,1,3,4,2};
cout << findDuplicate(nums) << endl;
}

Output:
2
3

Complexity
• Runtime: O(N), where N = nums.length.
• Extra space: O(1).

References
• https://leetcode.com/problems/find-the-duplicate-number/
• https://www.leetsolve.com/287-find-the-duplicate-number
Spiral Matrix II

Problem statement
Given a positive integer n, generate an n x n matrix filled with elements from 1 to n^2
in spiral order.

Example 1

Figure 3: The result matrix in Example 1


Input: n = 3
Output: [[1,2,3],[8,9,4],[7,6,5]]

Example 2
Input: n = 1
Output: [[1]]

Constraints
• 1 <= n <= 20.

Solution
1. Starting from the top left of the matrix.

33
34 SPIRAL MATRIX II

2. Going along the spiral direction.


3. Put the value to the matrix, starting from 1.

Code
#include <vector >
#include <iostream >
using namespace std;
enum Direction {RIGHT, DOWN, LEFT, UP};
vector<vector < int >> generateMatrix( int n) {
vector<vector < int >> m(n, vector < int >(n));
int bottom = n ‐ 1;
int right = n ‐ 1;
int top = 0;
int left = 0;
int row = 0;
int col = 0;
Direction d = RIGHT;
int a = 1;
while (top <= bottom && left <= right) {
m[row][col] = a++;
switch (d) {
case RIGHT:
if (col == right) {
top++;
d = DOWN;
row++;
} else {
col++;
}
break ;
case DOWN:
if (row == bottom) {
right ‐‐;
d = LEFT;
col‐‐;
} else {
row++;
}
break ;
case LEFT:
if (col == left) {
bottom ‐‐;
SOLUTION 35

d = UP;
row‐‐;
} else {
col‐‐;
}
break ;
case UP:
if (row == top) {
left++;
d = RIGHT;
col++;
} else {
row‐‐;
}
break ;
}
}
return m;
}
void printResult(vector <vector < int >>& m) {
cout << "[";
for ( auto & r : m) {
cout << "[";
for ( int a : r) {
cout << a << ",";
}
cout << "]";
}
cout << "]\n";
}
int main() {
auto m = generateMatrix(3);
printResult(m);
m = generateMatrix(1);
printResult(m);
}

Output:
[[1,2,3,][8,9,4,][7,6,5,]]
[[1,]]
36 SPIRAL MATRIX II

Complexity
• Runtime: O(n^2), where n x n is the size of the matrix.
• Extra space: O(1).

References
• https://leetcode.com/problems/spiral-matrix-ii/
• https://www.leetsolve.com/59-spiral-matrix-ii
Unique Paths

Problem statement
A robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram
below).
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 (marked ‘Finish’ in the diagram below).
How many possible unique paths are there?

Example 1

Figure 4: The setup of Example 1


Input: m = 3, n = 7
Output: 28

Example 2
Input: m = 3, n = 2
Output: 3
Explanation:
From the top‐left corner , there are a total of 3 ways to reach the
bottom ‐right corner:
1. Right ‐> Down ‐> Down
2. Down ‐> Down ‐> Right
3. Down ‐> Right ‐> Down

37
38 UNIQUE PATHS

Example 3
Input: m = 7, n = 3
Output: 28

Example 4
Input: m = 3, n = 3
Output: 6

Constraints
• 1 <= m, n <= 100.
• It’s guaranteed that the answer will be less than or equal to 2*10^9.

Solution 1: Recursive
At each point, the robot has two ways of moving: right or down. Let P(m,n) is the
wanted result. Then you have a recursive relationship:
P(m,n) = P(m‐1, n) + P(m, n‐1)

If the grid has only one row or only one column, then there is only one possible path.
P(1, n) = P(m, 1) = 1.

We have a recursive implementation.

Code
#include <iostream >
#include <vector >
using namespace std;
int uniquePaths( int m, int n) {
if (m == 1 || n == 1) {
return 1;
}
return uniquePaths(m ‐ 1, n) + uniquePaths(m, n ‐ 1);
}
int main() {
std::cout << uniquePaths(3,7) << std::endl;
std::cout << uniquePaths(7,3) << std::endl;
std::cout << uniquePaths(3,2) << std::endl;
std::cout << uniquePaths(3,3) << std::endl;
}
SOLUTION 2: DYNAMIC PROGRAMMING 39

Output:
28
28
3
6

Complexity
• Runtime: O(2^m + 2^n), where m*n is the size of the grid.
• Extra space: O(2^m + 2^n).

Solution 2: Dynamic programming


The recursive implementation repeats a lot of computations.
For example, uniquePaths(2,2) was recomputed in both uniquePaths(2,3) and
uniquePaths(3,2) when you compute uniquePaths(3,3).

One way of storing what has been computed is by using dynamic programming.

Code
#include <iostream >
#include <vector >
using namespace std;
int uniquePaths( int m, int n) {
vector<vector < int > > dp(m, vector < int >(n,1));
for ( int i = 1; i < m; i++) {
for ( int j = 1; j < n; j++) {
dp[i][j] = dp[i ‐ 1][j] + dp[i][j ‐ 1];
}
}
return dp[m ‐ 1][n ‐ 1];
}
int main() {
std::cout << uniquePaths(3,7) << std::endl;
std::cout << uniquePaths(7,3) << std::endl;
std::cout << uniquePaths(3,2) << std::endl;
std::cout << uniquePaths(3,3) << std::endl;
}

Output:
28
40 UNIQUE PATHS

28
3
6

Complexity
• Runtime: O(m*n), where m*n is the size of the grid.
• Extra space: O(m*n).

Solution 3: Reduced dynamic programming


You can rephrase the relationship inside the loop like this:
“new value” = “old value” + “previous value”;
Then you do not have to store all values of all rows.

Code
#include <iostream >
#include <vector >
using namespace std;
int uniquePaths( int m, int n) {
vector< int > dp(n, 1);
for ( int i = 1; i < m; i++) {
for ( int j = 1; j < n; j++) {
dp[j] += dp[j ‐ 1];
}
}
return dp[n ‐ 1];
}
int main() {
std::cout << uniquePaths(3,7) << std::endl;
std::cout << uniquePaths(7,3) << std::endl;
std::cout << uniquePaths(3,2) << std::endl;
std::cout << uniquePaths(3,3) << std::endl;
}

Output:
28
28
3
6
FINAL THOUGHT 41

Complexity
• Runtime: O(m*n).
• Extra space: O(n).

Final thought
I am wondering if there is some mathematics behind this problem. Please share your
finding if you find a formula for the solution to this problem.

References
• https://leetcode.com/problems/unique-paths/
• https://www.leetsolve.com/62-unique-paths
42 UNIQUE PATHS

You might also like