#include #include #include #include #include // Compute the sum of the squares of a number's digits. int sumOfSquaresOfDigits(int x) { int sum = 0; while (x > 0) { int digit = x % 10; sum += digit * digit; x /= 10; } return sum; } // std::unordered_set bool isGood_unordered_set(int n) { std::unordered_set visited; while (n != 1 && visited.find(n) == visited.end()) { visited.insert(n); n = sumOfSquaresOfDigits(n); } return (n == 1); } // std::unordered_map bool isGood_unordered_map(int n) { // We only need to mark that we have "seen" a number. // The bool value is arbitrary; storing true is enough. std::unordered_map visited; while (n != 1 && visited.find(n) == visited.end()) { visited[n] = true; // Mark n as visited n = sumOfSquaresOfDigits(n); } return (n == 1); } class MyHashSet { private: // store integers in a vector of lists std::vector< std::list > table; int num_elements; static const int DEFAULT_SIZE = 16; static const double LOAD_FACTOR_THRESHOLD; // A simple hash function for int int hashFunction(int key) const { // take abs value int h = key < 0 ? -key : key; return h % (int)table.size(); } void rehash() { int newSize = (int)table.size() * 2; // doubling std::vector< std::list > newTable(newSize); // re-insert all existing elements into newTable for (auto &chain : table) { for (int val : chain) { int h = (val < 0 ? -val : val) % newSize; newTable[h].push_back(val); } } table.swap(newTable); } void rehashIfNeeded() { // If load factor = num_elements / table.size() is too big, rehash double load_factor = (double)num_elements / (double)table.size(); if (load_factor > LOAD_FACTOR_THRESHOLD) { rehash(); } } public: // Constructor MyHashSet(int initialSize = DEFAULT_SIZE) : table(initialSize), num_elements(0) {} // Return true if key is found bool find(int key) const { int h = hashFunction(key); // Search the list in bin h for (int val : table[h]) { if (val == key) return true; } return false; } // Insert key if not already in the hash set void insert(int key) { if (!find(key)) { int h = hashFunction(key); table[h].push_back(key); num_elements++; rehashIfNeeded(); } } }; const double MyHashSet::LOAD_FACTOR_THRESHOLD = 1.0; // The "isGood" function that uses MyHashSet bool isGood_custom_hash(int n) { MyHashSet visited; while (n != 1 && !visited.find(n)) { visited.insert(n); n = sumOfSquaresOfDigits(n); } return (n == 1); } int main() { int testCases[] = {2,4,5,6,17,18,20,1,7,10,13,19,23,28,68}; std::cout << "=== Using std::unordered_set ===" << std::endl; for (int n : testCases) { if (isGood_unordered_set(n)) std::cout << n << " is a good number." << std::endl; else std::cout << n << " is not a good number." << std::endl; } std::cout << "\n=== Using std::unordered_map ===" << std::endl; for (int n : testCases) { if (isGood_unordered_map(n)) std::cout << n << " is a good number." << std::endl; else std::cout << n << " is not a good number." << std::endl; } std::cout << "\n=== Using custom separate-chaining HashSet ===" << std::endl; for (int n : testCases) { if (isGood_custom_hash(n)) std::cout << n << " is a good number." << std::endl; else std::cout << n << " is not a good number." << std::endl; } return 0; }