-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfirst_missing_positive.hpp
141 lines (113 loc) · 3.19 KB
/
first_missing_positive.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
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
// 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 source:
/// 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 <std::contiguous_iterator Itr>
requires std::sortable<Itr> and std::integral<std::iter_value_t<Itr>>
constexpr auto quasi_sort(Itr const first, Itr const src) noexcept -> void
{
using ValType = std::iter_value_t<Itr>;
if (auto const n{*src}; n > ValType{0})
{
auto const dest{first + std::max<ValType>(ValType{0}, n - ValType{1})};
if (auto const aux{*dest}; aux != n)
{
*dest = n;
*src = aux;
quasi_sort(first, src);
}
}
}
} // namespace detail
namespace base {
template <std::contiguous_iterator Itr, std::sized_sentinel_for<Itr> Sentinel>
requires std::sortable<Itr> and std::integral<std::iter_value_t<Itr>>
[[nodiscard]] constexpr auto
lowest_missing(Itr const begin, Sentinel const end) noexcept
-> std::iter_value_t<Itr>
{
using ValType = std::iter_value_t<Itr>;
auto max{end - begin};
for (auto itr{begin}; itr != end; ++itr)
{
if (auto const current{*itr}; current < ValType{1})
{
--max;
}
else if (current > max)
{
--max;
*itr = ValType{0};
}
else
{
detail::quasi_sort(begin, itr);
}
}
ValType min_num{1};
auto const endItr{begin + max};
for (auto itr{begin}; itr != endItr; ++itr)
{
if (*itr == min_num)
{
++min_num;
}
}
return min_num;
}
} // namespace base
namespace fast {
template <std::contiguous_iterator Itr, std::sized_sentinel_for<Itr> Sentinel>
requires std::sortable<Itr> and std::integral<std::iter_value_t<Itr>>
[[nodiscard]] constexpr auto
lowest_missing(Itr const begin, Sentinel const end) noexcept
-> std::iter_value_t<Itr>
{
using ValType = std::iter_value_t<Itr>;
auto max{end - begin};
for (auto itr{begin}; itr != end; ++itr)
{
if (auto const current{*itr}; current < ValType{1})
{
--max;
}
else if (current > max)
{
--max;
*itr = ValType{0};
}
else
{
detail::quasi_sort(begin, itr);
}
}
ValType min_num{1};
for (std::iter_difference_t<Itr> i{0}; i < max; ++i)
{
if (begin[i] == min_num)
{
++min_num;
}
}
return min_num;
}
} // namespace fast
} // namespace forfun::first_missing_positive
#endif // FORFUN_FIRST_MISSING_POSITIVE_HPP_