DEV Community

Cover image for Modern C++ for LeetCode πŸ§‘β€πŸ’»πŸš€

Modern C++ for LeetCode πŸ§‘β€πŸ’»πŸš€

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 {};
}
Enter fullscreen mode Exit fullscreen mode

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();
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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)