This repository has been archived by the owner on Feb 6, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathlongest_increasing_subsequence.hpp
102 lines (86 loc) · 3.03 KB
/
longest_increasing_subsequence.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// Andrew Naplavkov
#ifndef STEP_LONGEST_INCREASING_SUBSEQUENCE_HPP
#define STEP_LONGEST_INCREASING_SUBSEQUENCE_HPP
#include <algorithm>
#include <functional>
#include <iterator>
#include <optional>
#include <unordered_map>
#include <vector>
namespace step::longest_increasing_subsequence {
namespace detail {
class increasing_subsequences {
std::vector<size_t> tails_;
std::unordered_map<size_t, std::optional<size_t>> prevs_;
public:
template <class RandomIt, class Compare>
increasing_subsequences(RandomIt first, RandomIt last, Compare cmp)
{
for (size_t i = 0, size = std::distance(first, last); i < size; ++i) {
auto tail = std::upper_bound(
tails_.begin(), tails_.end(), i, [&](size_t lhs, size_t rhs) {
return cmp(first[lhs], first[rhs]);
});
if (tail == tails_.begin())
prevs_[i] = std::nullopt;
else
prevs_[i] = *std::prev(tail);
if (tail == tails_.end())
tails_.push_back(i);
else
*tail = i;
}
}
auto longest() const
{
std::vector<size_t> result;
auto i = tails_.empty() ? std::nullopt : std::optional{tails_.back()};
for (; i; i = prevs_.at(i.value()))
result.push_back(i.value());
std::reverse(result.begin(), result.end());
return result;
}
};
} // namespace detail
/// Find longest increasing subsequence (LIS) in the array.
/// The subsequence's elements are in sorted order, lowest to highest.
/// This subsequence is not necessarily contiguous, or unique.
/// Reorders the elements in such a way that all elements for the subsequence
/// precede the others.
/// @return iterator to the end of the subsequence.
/// Time complexity O(N*log(N)), space complexity O(N), where:
/// N = std::distance(first, last).
/// @see https://en.wikipedia.org/wiki/Longest_increasing_subsequence
/// @see
/// https://www.geeksforgeeks.org/longest-monotonically-increasing-subsequence-size-n-log-n/
template <class RandomIt, class Compare>
auto partition(RandomIt first, RandomIt last, Compare&& cmp)
{
using std::swap;
auto it = first;
for (auto i :
detail::increasing_subsequences{
first, last, std::forward<Compare>(cmp)}
.longest())
swap(first[i], *it++);
return it;
}
template <class RandomIt>
auto partition(RandomIt first, RandomIt last)
{
return longest_increasing_subsequence::partition(first, last, std::less{});
}
template <class RandomRng, class Compare>
auto partition(RandomRng& rng, Compare&& cmp)
{
return longest_increasing_subsequence::partition(
std::begin(rng), std::end(rng), std::forward<Compare>(cmp));
}
template <class RandomRng>
auto partition(RandomRng& rng)
{
return longest_increasing_subsequence::partition(std::begin(rng),
std::end(rng));
}
} // namespace step::longest_increasing_subsequence
#endif // STEP_LONGEST_INCREASING_SUBSEQUENCE_HPP