C++ has come a long way since its early days, and the "modern" C++ (starting with C++11 and beyond) offers a host of features that make solving problems on platforms like LeetCode way more efficient and enjoyable. Forget manual memory management, verbose loops, and cryptic pointer arithmetic! Modern C++ gives us tools like std::unordered_map, range-based loops, and lambda functions that let us focus more on solving problems and less on boilerplate code. Let's dive into some common algorithmic patterns and see how modern C++ makes them awesome! π‘
1. Hashmaps (using std::unordered_map) πΊοΈ
In old-school C, implementing a hash map meant writing your own data structure with hashing functions, collision handling, and all that jazz. Not anymore! Modern C++ gives us std::unordered_map, which is fast and easy to use.
Example: Two Sum (LeetCode #1)
#include <unordered_map>
#include <vector>
std::vector<int> twoSum(const std::vector<int>& nums, int target) {
std::unordered_map<int, int> map; // Key: number, Value: index
for (int i = 0; i < nums.size(); ++i) {
int complement = target - nums[i];
if (map.count(complement)) { // Check if complement exists in map
return {map[complement], i};
}
map[nums[i]] = i;
}
return {};
}
Why itβs awesome:
Fast lookups: Average O(1) for key-value lookups.
No need to write custom hash functions or deal with memory allocation.
2. Binary Search (using std::binary_search) π
Binary search is a classic algorithm, but in C++, we get helper functions from the header that make life easier.
Example: Search Insert Position (LeetCode #35)
#include <vector>
#include <algorithm>
int searchInsert(const std::vector<int>& nums, int target) {
return std::lower_bound(nums.begin(), nums.end(), target) - nums.begin();
}
Why itβs awesome:
std::lower_bound
: Finds the first element not less than the target.
Clean and concise: No more manually tracking low, high, and mid pointers.
3. Quicksort (using std::sort) β‘
While implementing quicksort manually is a fun exercise, it's not something you want to do in every LeetCode problem. Modern C++ has std::sort
, which is highly optimized.
Example: Sort an Array (LeetCode #912)
#include <vector>
#include <algorithm>
std::vector<int> sortArray(std::vector<int>& nums) {
std::sort(nums.begin(), nums.end());
return nums;
}
Why itβs awesome:
Under the hood, std::sort
uses a hybrid of quicksort, heapsort, and insertion sort.
Efficient and portable: Optimized for real-world performance.
4. Two Pointer Technique (Range-based Loops + std::string Utilities) πββοΈπββοΈ
The two-pointer technique is perfect for problems involving arrays or strings. Modern C++ makes it easier with range-based loops and helper functions for strings.
Example: Valid Palindrome (LeetCode #125)
#include <string>
#include <cctype>
bool isPalindrome(const std::string& s) {
int left = 0, right = s.size() - 1;
while (left < right) {
while (left < right && !std::isalnum(s[left])) ++left;
while (left < right && !std::isalnum(s[right])) --right;
if (std::tolower(s[left]) != std::tolower(s[right])) return false;
++left; --right;
}
return true;
}
Why itβs awesome:
std::isalnum
and std::tolower
: Built-in utilities to handle character checks.
No need for manual ASCII checks!
5. Graphs (using std::queue and std::vector) π
Graph problems often involve BFS or DFS. Modern C++ shines here with containers like std::vector for adjacency lists and std::queue for BFS.
Example: Number of Islands (LeetCode #200)
#include <vector>
#include <queue>
void bfs(std::vector<std::vector<char>>& grid, int r, int c) {
std::queue<std::pair<int, int>> q;
q.push({r, c});
grid[r][c] = '0'; // Mark visited
std::vector<std::pair<int, int>> directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
while (!q.empty()) {
auto [row, col] = q.front(); q.pop();
for (const auto& [dr, dc] : directions) {
int nr = row + dr, nc = col + dc;
if (nr >= 0 && nr < grid.size() && nc >= 0 && nc < grid[0].size() && grid[nr][nc] == '1') {
q.push({nr, nc});
grid[nr][nc] = '0';
}
}
}
}
int numIslands(std::vector<std::vector<char>>& grid) {
int count = 0;
for (int r = 0; r < grid.size(); ++r) {
for (int c = 0; c < grid[0].size(); ++c) {
if (grid[r][c] == '1') {
++count;
bfs(grid, r, c);
}
}
}
return count;
}
Why itβs awesome:
std::queue
: Great for BFS, abstracts away all the pointer/memory headache.
Pair destructuring with [row, col]: Clean and readable code.
Conclusion π
Modern C++ takes away much of the boilerplate coding and error-prone manual work that was once necessary. Whether it's hash maps, sorting, or handling strings and graphs, these new features let you focus on problem-solving instead of fighting the language.
TL;DR of Modern C++ Features:
- std::unordered_map: O(1) lookups!
- std::lower_bound and std::sort: Simplifies search and sorting.
- Range-based loops, lambdas, and std::string utilities: Cleaner, safer, and faster code.
- std::vector and std::queue: Perfect for graphs, dynamic arrays, and more.
Now grab your favorite cup of coffee β and start smashing those LeetCode problems!
Top comments (0)