-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfirst_missing_positive.hpp
More file actions
157 lines (126 loc) · 3.52 KB
/
first_missing_positive.hpp
File metadata and controls
157 lines (126 loc) · 3.52 KB
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// Copyright (c) Omar Boukli-Hacene. All rights reserved.
// Distributed under an MIT-style license that can be
// found in the LICENSE file.
// SPDX-License-Identifier: MIT
/// Problem sources:
/// - https://simontoth.substack.com/p/daily-bite-of-c-smallest-missing
/// - https://compiler-explorer.com/z/G7r4rebhd
///
/// Given a list of integers, determine the smallest missing
/// positive integer.
///
/// Importantly your solution must run in O(n) time, and while
/// you are permitted to modify the input, you can only use
/// constant additional memory.
#ifndef FORFUN_FIRST_MISSING_POSITIVE_HPP_
#define FORFUN_FIRST_MISSING_POSITIVE_HPP_
#include <algorithm>
#include <concepts>
#include <iterator>
namespace forfun::first_missing_positive {
namespace detail {
template <typename Iter>
requires std::contiguous_iterator<Iter>
and std::sortable<Iter>
and std::integral<std::iter_value_t<Iter>>
constexpr auto quasi_sort(Iter const first, Iter const src) noexcept -> void
{
using std::max;
using ValType = std::iter_value_t<Iter>;
if (auto const num{*src}; num > ValType{})
{
auto const dest{first + max<ValType>(ValType{}, num - ValType{1})};
if (auto const aux{*dest}; aux != num)
{
*dest = num;
*src = aux;
quasi_sort(first, src);
}
}
}
} // namespace detail
namespace base {
template <typename Iter, typename Sentinel>
requires std::contiguous_iterator<Iter>
and std::sized_sentinel_for<Iter, Sentinel>
and std::sortable<Iter>
and std::integral<std::iter_value_t<Iter>>
[[nodiscard]] constexpr auto
lowest_missing(Iter const first, Sentinel const last) noexcept
-> std::iter_value_t<Iter>
{
using std::distance;
using std::next;
using ValType = std::iter_value_t<Iter>;
auto max{distance(first, last)};
for (auto iter{first}; iter != last; ++iter)
{
if (auto const current{*iter}; current < ValType{1})
{
--max;
}
else if (current > max)
{
--max;
*iter = ValType{};
}
else
{
detail::quasi_sort(first, iter);
}
}
ValType min_num{1};
auto const end_iter{next(first, max)};
for (auto iter{first}; iter != end_iter; ++iter)
{
if (*iter == min_num)
{
++min_num;
}
}
return min_num;
}
} // namespace base
namespace fast {
template <typename Iter, typename Sentinel>
requires std::contiguous_iterator<Iter>
and std::sized_sentinel_for<Iter, Sentinel>
and std::sortable<Iter>
and std::integral<std::iter_value_t<Iter>>
[[nodiscard]] constexpr auto
lowest_missing(Iter const first, Sentinel const last) noexcept
-> std::iter_value_t<Iter>
{
using std::distance;
using std::next;
using ValType = std::iter_value_t<Iter>;
auto max{distance(first, last)};
for (auto iter{first}; iter != last; ++iter)
{
if (auto const current{*iter}; current < ValType{1})
{
--max;
}
else if (current > max)
{
--max;
*iter = ValType{};
}
else
{
detail::quasi_sort(first, iter);
}
}
ValType min_num{1};
for (std::iter_difference_t<Iter> i{}; i < max; ++i)
{
if (*next(first, i) == min_num)
{
++min_num;
}
}
return min_num;
}
} // namespace fast
} // namespace forfun::first_missing_positive
#endif // FORFUN_FIRST_MISSING_POSITIVE_HPP_