-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlast_stone_weight.hpp
162 lines (125 loc) · 3.78 KB
/
last_stone_weight.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
// 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://leetcode.com/problems/last-stone-weight/description/
#ifndef FORFUN_LAST_STONE_WEIGHT_HPP_
#define FORFUN_LAST_STONE_WEIGHT_HPP_
#include <algorithm>
#include <concepts>
#include <functional>
#include <iterator>
#include <vector>
namespace forfun::last_stone_weight {
namespace naive {
/// Assume stones is not empty, and each element (stone) of stones is
/// non-negative, otherwise the function's behavior is undefined.
template <std::contiguous_iterator Iter, std::sentinel_for<Iter> Sentinel>
requires std::integral<std::iter_value_t<Iter>>
[[nodiscard]] constexpr auto
last_stone_weight(Iter const first, Sentinel last) noexcept
-> std::iter_value_t<Iter>
{
using ValueType = std::iter_value_t<Iter>;
if (first == last) [[unlikely]]
{
return ValueType{0};
}
ValueType s1{*first};
auto stop{first};
for (++stop; stop != last;)
{
ValueType s2{0};
auto it_s1{last};
auto it_s2{last};
s1 = ValueType{0};
// Find the heaviest two stones, where s1 is larger than or equal to s2.
for (auto it{first}; it != last; ++it)
{
if (*it >= s1)
{
s2 = s1;
s1 = *it;
it_s2 = it_s1;
it_s1 = it;
}
else if (*it >= s2)
{
s2 = *it;
it_s2 = it;
}
}
// Smash the two stones together.
*it_s1 -= *it_s2;
--last;
if (stop != last)
{
*it_s2 = *last;
}
s1 = *it_s1;
}
return s1;
}
} // namespace naive
namespace heapified {
/// Assume each element (stone) of stones is non-negative, otherwise the
/// function's behavior is undefined.
template <std::contiguous_iterator Iter, std::sentinel_for<Iter> Sentinel>
requires std::integral<std::iter_value_t<Iter>>
[[nodiscard]] constexpr auto
last_stone_weight(Iter const first, Sentinel last) noexcept
-> std::iter_value_t<Iter>
{
using ValueType = std::iter_value_t<Iter>;
using DiffType = decltype(last - first);
std::make_heap(first, last);
auto size{last - first};
while (size > DiffType{1})
{
auto s{*first};
std::pop_heap(first, last--);
s -= *first;
std::pop_heap(first, last--);
if (s != ValueType{0})
{
*last = s;
++last;
std::push_heap(first, last);
}
size = last - first;
}
return size == DiffType{0} ? ValueType{0} : *first;
}
} // namespace heapified
namespace priority_queue_based {
/// Assume each element (stone) of stones is non-negative, otherwise the
/// function's behavior is undefined.
[[nodiscard]] auto last_stone_weight(std::vector<int>&& stones) noexcept -> int;
} // namespace priority_queue_based
namespace sort_based {
/// Assume stones is not empty, and each element (stone) of stones is
/// non-negative, otherwise the function's behavior is undefined.
template <std::contiguous_iterator Iter, std::sentinel_for<Iter> Sentinel>
requires std::integral<std::iter_value_t<Iter>>
[[nodiscard]] constexpr auto
last_stone_weight(Iter const first, Sentinel last) noexcept
-> std::iter_value_t<Iter>
{
if (first == last) [[unlikely]]
{
return 0;
}
auto second{first};
++second;
for (; second != last;)
{
std::sort(first, last, std::greater<>());
*first -= *second;
*second = *--last;
}
return *first;
}
} // namespace sort_based
} // namespace forfun::last_stone_weight
#endif // FORFUN_LAST_STONE_WEIGHT_HPP_