Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "Top 10 Algorithms" examples #114

Merged
merged 5 commits into from
Aug 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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