Skip to content

Commit

Permalink
Merge pull request #114 from tcbrindle/pr/top10_examples
Browse files Browse the repository at this point in the history
Add "Top 10 Algorithms" examples
  • Loading branch information
tcbrindle authored Aug 9, 2023
2 parents 49c0f3c + 67b2862 commit c10ed6b
Show file tree
Hide file tree
Showing 12 changed files with 478 additions and 0 deletions.
12 changes: 12 additions & 0 deletions example/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,15 @@ add_example(example-docs-set-union docs/set_union.cpp)
add_example(example-docs-scan-first docs/scan_first.cpp)
add_example(example-docs-starts-with docs/starts_with.cpp)
add_example(example-docs-unfold docs/unfold.cpp)

add_example(example-top10-rain-water top10/01_trapping_rain_water.cpp)
add_example(example-top10-mco top10/02_max_consecutive_ones.cpp)
add_example(example-top10-lcis top10/03_longest_continuous_increasing_subsequence.cpp)
add_example(example-top10-kadanes top10/04_maximum_subarray_sum.cpp)
add_example(example-top10-sushi top10/05_sushi_for_two.cpp)
add_example(example-top10-max-gap top10/06_max_gap.cpp)
add_example(example-top10-max-gap-count top10/07_max_gap_count.cpp)
add_example(example-top10-tco top10/08_three_consecutive_odds.cpp)
add_example(example-top10-skyline top10/09_skyline.cpp)
add_example(example-top10-ocean-view top10/10_ocean_view.cpp)

43 changes: 43 additions & 0 deletions example/top10/01_trapping_rain_water.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

// Copyright (c) 2023 Tristan Brindle (tcbrindle at gmail dot com)
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

/*
* Given n non-negative integers representing an elevation map where the width
* of each bar is 1, compute how much water it can trap after raining.
*
* https://leetcode.com/problems/trapping-rain-water/
*
*/

#include <flux.hpp>

#include <algorithm>

auto const rain_water = [](std::initializer_list<int> heights)
{
// Find the index of the maximum height
flux::cursor auto max_idx = flux::find_max(heights);

// Split the input sequence into two at the max position
auto left = flux::slice(heights, flux::first(heights), max_idx);
auto right = flux::slice(heights, max_idx, flux::last(heights));

// To calculate the trapped rain water for each half, we sum up the
// difference between each element and the maximum seen up to that point
auto trapped = [](flux::sequence auto seq) {
return flux::zip(flux::scan(seq, flux::cmp::max), seq)
.map(flux::unpack(std::minus{}))
.sum();
};

// The final answer is the total of the trapped rain water reading
// left-to-right for the left half, and right-to-left for the right half
return trapped(left) + trapped(flux::reverse(right));
};

static_assert(rain_water({0,1,0,2,1,0,1,3,2,1,2,1}) == 6);
static_assert(rain_water({4,2,0,3,2,5}) == 9);

int main() {}
45 changes: 45 additions & 0 deletions example/top10/02_max_consecutive_ones.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

// Copyright (c) 2023 Tristan Brindle (tcbrindle at gmail dot com)
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

/*
* Given a binary array nums, return the maximum number of consecutive 1's in the array.
*
* https://leetcode.com/problems/max-consecutive-ones/
*/

#include <flux.hpp>

namespace version1 {

auto const mco = [](std::initializer_list<int> nums)
{
return flux::ref(nums)
.chunk_by(std::equal_to{})
.map(flux::sum)
.max()
.value_or(0);
};

static_assert(mco({1,1,0,1,1,1}) == 3);
static_assert(mco({1,0,1,1,0,1}) == 2);

}

namespace version2 {

auto const mco = [](std::initializer_list<int> nums)
{
return flux::ref(nums)
.scan([](int count, int i) { return i * (count + i); })
.max()
.value_or(0);
};

static_assert(mco({1,1,0,1,1,1}) == 3);
static_assert(mco({1,0,1,1,0,1}) == 2);

}

int main() {}
29 changes: 29 additions & 0 deletions example/top10/03_longest_continuous_increasing_subsequence.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

// Copyright (c) 2023 Tristan Brindle (tcbrindle at gmail dot com)
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

/*
* Given an unsorted array of integers nums, return the length of the longest
* continuous increasing subsequence (i.e. subarray). The subsequence must be
* strictly increasing.
*
* https://leetcode.com/problems/longest-continuous-increasing-subsequence/
*/

#include <flux.hpp>

auto const lcis = [](std::initializer_list<int> nums)
{
return flux::ref(nums)
.chunk_by(std::less{})
.map(flux::count)
.max()
.value_or(0);
};

static_assert(lcis({}) == 0);
static_assert(lcis({1, 3, 5, 4, 7}) == 3); // [1, 3, 5]
static_assert(lcis({2, 2, 2, 2, 2}) == 1); // [2] (must be strictly increasing)

int main() {}
28 changes: 28 additions & 0 deletions example/top10/04_maximum_subarray_sum.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@

// Copyright (c) 2023 Tristan Brindle (tcbrindle at gmail dot com)
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

/*
* Given an integer array nums, find the subarray with the largest sum, and
* return its sum.
*
* https://leetcode.com/problems/maximum-subarray/
*
*/

#include <flux.hpp>

auto const kadanes = [](std::initializer_list<int> nums)
{
return flux::ref(nums)
.scan([](int sum, int i) { return std::max(i, sum + i); })
.max()
.value_or(0);
};

static_assert(kadanes({-2, 1, -3, 4, -1, 2, 1, -5, 4}) == 6);
static_assert(kadanes({1}) == 1);
static_assert(kadanes({5, 4, -1, 7, 8}) == 23);

int main() {}
27 changes: 27 additions & 0 deletions example/top10/05_sushi_for_two.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

// Copyright (c) 2023 Tristan Brindle (tcbrindle at gmail dot com)
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

/*
* https://codeforces.com/contest/1138/problem/A
*/

#include <flux.hpp>

auto const sushi_for_two = [](std::initializer_list<int> sushi)
{
return 2 * flux::ref(sushi)
.chunk_by(std::equal_to{})
.map(flux::count)
.pairwise_map(flux::cmp::min)
.max()
.value_or(0);
};

static_assert(sushi_for_two({}) == 0);
static_assert(sushi_for_two({2, 2, 2, 1, 1, 2, 2}) == 4);
static_assert(sushi_for_two({1, 2, 1, 2, 1, 2}) == 2);
static_assert(sushi_for_two({2, 2, 1, 1, 1, 2, 2, 2, 2}) == 6);

int main() {}
39 changes: 39 additions & 0 deletions example/top10/06_max_gap.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

// Copyright (c) 2023 Tristan Brindle (tcbrindle at gmail dot com)
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

/*
* https://leetcode.com/problems/maximum-gap/
*
* Note that the original problem specifies that the solution should have O(N)
* runtime and use O(N) extra space. We instead use an O(NlogN) solution as
* discussed on ADSP episode 115 (https://adspthepodcast.com/2023/02/03/Episode-115.html)
* The NlogN version still passes the time limit constraints on leetcode, however.
*/

#include <flux.hpp>

#include <cassert>

namespace {

// std::abs is not constexpr in C++20
auto const abs = [](std::signed_integral auto i) { return i < 0 ? -i : i; };

auto const max_gap = [](std::vector<int> nums)
{
flux::sort(nums);
return flux::ref(nums)
.pairwise_map([](int a, int b) { return abs(a - b); })
.max()
.value_or(0);
};

}

int main()
{
assert(max_gap({3, 6, 9, 1}) == 3);
assert(max_gap({10}) == 0);
}
91 changes: 91 additions & 0 deletions example/top10/07_max_gap_count.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@

// Copyright (c) 2023 Tristan Brindle (tcbrindle at gmail dot com)
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

/*
* https://theweeklychallenge.org/blog/perl-weekly-challenge-198/
*
* Also discussed on ADSP episode 116 (https://adspthepodcast.com/2023/02/03/Episode-116.html)
*/

#include <flux.hpp>

#include <cassert>

// GCC 11 doesn't support constexpr std::vector
#if defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE < 12
#define COMPILER_IS_GCC11
#endif

// std::abs is not constexpr in C++20
auto const c_abs = [](std::signed_integral auto i) { return i < 0 ? -i : i; };

namespace version1 {

// Sort + two passes
auto const max_gap_count = [](std::vector<int> nums)
{
flux::sort(nums);

auto diffs = flux::ref(nums).pairwise_map([](int a, int b) { return c_abs(a - b); });

return diffs.count_eq(diffs.max().value_or(0));
};

#ifndef COMPILER_IS_GCC11
static_assert(max_gap_count({2, 5, 8, 1}) == 2);
static_assert(max_gap_count({3, 6, 9, 1}) == 2);
static_assert(max_gap_count({10}) == 0);
#endif

}

namespace version2 {

// Sort + one pass
auto const max_gap_count = [](std::vector<int> nums)
{
struct max_count {
int value;
int count;
};

flux::sort(nums);
return flux::ref(nums)
.pairwise_map([](int a, int b) { return c_abs(a - b); })
.fold([](max_count max, int i) {
if (i > max.value) {
max = max_count{i, 1};
} else if (i == max.value ){
++max.count;
}
return max;
}, max_count{})
.count;
};

#ifndef COMPILER_IS_GCC11
static_assert(max_gap_count({2, 5, 8, 1}) == 2);
static_assert(max_gap_count({3, 6, 9, 1}) == 2);
static_assert(max_gap_count({10}) == 0);
#endif

}

int main()
{
{
using namespace version1;
assert(max_gap_count({2, 5, 8, 1}) == 2);
assert(max_gap_count({3, 6, 9, 1}) == 2);
assert(max_gap_count({10}) == 0);
}

{
using namespace version2;
assert(max_gap_count({2, 5, 8, 1}) == 2);
assert(max_gap_count({3, 6, 9, 1}) == 2);
assert(max_gap_count({10}) == 0);
}
}
Loading

0 comments on commit c10ed6b

Please sign in to comment.