LeetCode/cpp/greatest-common-divisor-traversal.cpp

159 lines
3.4 KiB
C++
Raw Permalink Normal View History

#include <algorithm>
#include <cmath>
#include <unordered_map>
#include <vector>
namespace {
struct factors_iterator {
factors_iterator() : f(-1) {}
factors_iterator(int f, int n) : f(f), n(n), upper(std::sqrt(n)) {}
auto operator!=(const factors_iterator &other) const -> bool {
return f != other.f;
}
auto operator*() const -> int { return f; }
auto operator++() -> factors_iterator & {
// f yielded a prime
if (f > upper || n == 1) {
f = -1;
return *this;
}
do {
++f;
} while (f <= upper && n % f != 0);
// n is a prime
if (f > upper) {
f = n;
}
while (n % f == 0) {
n /= f;
}
return *this;
}
private:
int f;
int n;
int upper;
};
struct factors {
factors(int n) : n(n) {}
auto begin() const -> factors_iterator { return ++factors_iterator(1, n); }
auto end() const -> factors_iterator { return factors_iterator(); }
private:
int n;
};
void dfs(std::unordered_map<int, std::vector<int>> &graph,
std::vector<bool> &visited, int u) {
visited[u] = true;
for (auto v : graph[u]) {
if (!visited[v]) {
dfs(graph, visited, v);
}
}
}
} // namespace
class Solution {
public:
bool canTraverseAllPairs(const std::vector<int> &nums) {
auto n = nums.size();
std::unordered_map<int, int> gcd;
std::unordered_map<int, std::vector<int>> neighbors;
for (auto i = 0u; i < n; ++i) {
for (auto f : factors(nums[i])) {
if (gcd.contains(f)) {
int u = i;
int v = gcd[f];
neighbors[u].push_back(v);
neighbors[v].push_back(u);
}
gcd[f] = i;
}
}
std::vector<bool> visited(n, false);
dfs(neighbors, visited, 0);
return std::find(visited.begin(), visited.end(), false) ==
visited.end();
}
};
#ifdef _MF_TEST
#include <gtest/gtest.h>
TEST(examples, no_1) {
Solution s;
EXPECT_TRUE(s.canTraverseAllPairs(std::vector{2, 3, 6}));
}
TEST(examples, no_2) {
Solution s;
EXPECT_FALSE(s.canTraverseAllPairs(std::vector{3, 9, 5}));
}
TEST(examples, no_3) {
Solution s;
EXPECT_TRUE(s.canTraverseAllPairs(std::vector{4, 3, 12, 8}));
}
TEST(factors, prime_2) {
std::vector<int> fs;
for (auto f : factors(2)) {
fs.push_back(f);
}
EXPECT_EQ(fs, std::vector{2});
}
TEST(factors, prime_7) {
std::vector<int> fs;
for (auto f : factors(7)) {
fs.push_back(f);
}
EXPECT_EQ(fs, std::vector{7});
}
TEST(factors, prime_29) {
std::vector<int> fs;
for (auto f : factors(29)) {
fs.push_back(f);
}
EXPECT_EQ(fs, std::vector{29});
}
TEST(factors, composite_6) {
std::vector<int> fs;
for (auto f : factors(6)) {
fs.push_back(f);
}
EXPECT_EQ(fs, (std::vector{2, 3}));
}
TEST(factors, composite_15) {
std::vector<int> fs;
for (auto f : factors(15)) {
fs.push_back(f);
}
EXPECT_EQ(fs, (std::vector{3, 5}));
}
TEST(factors, composite_1024) {
std::vector<int> fs;
for (auto f : factors(1024)) {
fs.push_back(f);
}
EXPECT_EQ(fs, std::vector{2});
}
int main(int argc, char **argv) {
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
#endif