10 Classic Coding Challenges Book
10 Classic Coding Challenges Book
Challenges
Essential Problem Solving Skills, Fundamental Algorithms,
Basic Data Structures and C++ Programming Language
July 2022
ii
Contents
Single Number 9
Majority Element 13
Valid Parentheses 21
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
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 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
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).
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.
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
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
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?
13
14 MAJORITY ELEMENT
Output:
3
2
Complexity
• Runtime: O(n), where n = nums.length.
• Extra space: O(n).
}
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"].
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'
Code
SOLUTION: FINDING THE PATTERN 19
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,
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.
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
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.)
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).
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
Output:
2
3
Complexity
• Runtime: O(N), where N = nums.length.
• Extra space: O(logN). std::vector<bool>2 is optimized for space-efficient.
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
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
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
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.
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).
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).
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