God Emperor Leto
Senior Member
Vẫn phải nhập manual Result type chứ không tự deduce bằng invoke_result_t được ví lúc đó 2 type bị phụ thuộc vòng: lambda phụ thuộc Cache, Cache lại phụ thuộc lambda.
[/spoler]C++:namespace std { namespace { template <typename T> inline size_t hash_combine(size_t seed, T&& v) { return seed ^= hash<remove_cv_t<remove_reference_t<T>>>()(forward<T>(v)) + 0x9e3779b9 + (seed<<6) + (seed>>2); } template <typename Tuple, size_t Index = tuple_size<Tuple>::value - 1> struct TupleHash { static size_t calculate(size_t seed, Tuple const &t) { seed = TupleHash<Tuple, Index - 1>::calculate(seed, t); return hash_combine(seed, std::get<Index>(t)); } }; template <typename Tuple> struct TupleHash<Tuple, 0> { static size_t calculate(size_t seed, Tuple const &t) { return hash_combine(seed, std::get<0>(t)); } }; } // namespace template <typename... Args> struct hash<tuple<Args...>> { size_t operator()(tuple<Args...> const &tt) const { return TupleHash<tuple<Args...>>::calculate(0, tt); } }; } // namespace std template <typename RecursiveFunc, typename Result, typename... Args> class Cache { using Params = std::tuple<Args...>; // using Result = std::invoke_result_t<RecursiveFunc, Cache&, Args...>; public: Cache(RecursiveFunc&& f) : f{std::move(f)} {} void set(Result value, Args&&... args) { data[std::make_tuple(std::forward<Args>(args)...)] = value; } Result operator[](Args&&... args) { auto t = std::make_tuple(std::forward<Args>(args)...); if (auto it = data.find(t); it != data.end()) return it->second; return data[t] = f(*this, std::forward<Args>(args)...); } private: std::unordered_map<Params, Result> data; RecursiveFunc f; }; using namespace std; class Solution { public: int combinationSum4(vector<int>& nums, int target) { auto f = [&](auto& cache, uint32_t target){ uint32_t res = 0; for (uint32_t n : nums) if (target >= n) res += cache[target - n]; return res; }; Cache<decltype(f), uint32_t, uint32_t> m{std::move(f)}; m.set(1, 0); return m[target]; } };
sửa lại cho ngắn hơn
C++:
namespace std {
namespace {
template <class T>
size_t hash_combine(size_t seed, const T& v) {
return seed ^= hash<T>{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
} // namespace
template <class... Args>
struct hash<tuple<Args...>> {
template <size_t Index = sizeof...(Args) - 1>
size_t operator()(const tuple<Args...>& t, size_t seed = 0) const {
if constexpr (Index == 0) {
return hash_combine(seed, get<0>(t));
} else {
seed = operator()<Index - 1>(t, seed);
return hash_combine(seed, get<Index>(t));
}
}
};
} // namespace std
template <class RecursiveFunc, class Result, class... Args>
class Memo {
using Params = std::tuple<Args...>;
public:
explicit Memo(RecursiveFunc&& f) : f{move(f)} {}
Result operator()(Args... args) {
Params t = std::forward_as_tuple(args...);
auto it = cache.find(t);
if (it == end(cache))
std::tie(it, std::ignore) = cache.emplace(std::move(t), f(*this, std::forward<Args>(args)...));
return it->second;
}
private:
RecursiveFunc f;
std::unordered_map<Params, Result> cache;
};
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
auto f = [&](auto& f, int target) -> uint32_t {
if (target == 0) return 1;
uint32_t res = 0;
for (int n : nums) if (target >= n) res += f(target - n);
return res;
};
return Memo<decltype(f), uint32_t, int>{move(f)}(target);
}
};
ko cần cái hàm set kia làm gì nữa
C++:
if (target == 0) return 1;
uint32_t res = 0;
for (int n : nums) if (target >= n) res += f(target - n);
return res;
dòng
C++:
return Memo<decltype(f), uint32_t, int>{move(f)}(target);
có lẽ CRTP làm được nhưng phải viết class kế thừa vào, phải lấy cái nums kia qua ctor, ko gọn bằng [&]
---
edit: lấy ResultType được kìa
C++:
namespace std {
namespace {
template <class T>
size_t hash_combine(size_t seed, const T& v) {
return seed ^= hash<T>{}(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
} // namespace
template <class... Args>
struct hash<tuple<Args...>> {
template <size_t Index = sizeof...(Args) - 1>
size_t operator()(const tuple<Args...>& t, size_t seed = 0) const {
if constexpr (Index == 0) {
return hash_combine(seed, get<0>(t));
} else {
seed = operator()<Index - 1>(t, seed);
return hash_combine(seed, get<Index>(t));
}
}
};
} // namespace std
template <class RecursiveFunc, class... Args>
class Memo {
using Params = std::tuple<std::remove_cv_t<std::remove_reference_t<Args>>...>;
using Result = std::result_of_t<RecursiveFunc(Memo<RecursiveFunc, Args...>&, Args...)>;
public:
explicit Memo(RecursiveFunc&& f) : f{std::move(f)} {}
Result operator()(Args... args) {
Params t = std::forward_as_tuple(args...);
auto it = cache.find(t);
if (it == end(cache))
std::tie(it, std::ignore) = cache.emplace(std::move(t), f(*this, std::forward<Args>(args)...));
return it->second;
}
private:
RecursiveFunc f;
std::unordered_map<Params, Result> cache;
};
template <class RecursiveFunc, class... Args>
auto memoize(RecursiveFunc/*&&*/ f, Args/*&&*/... args) {
return Memo<RecursiveFunc, Args...>{std::move(f)}(std::forward<Args>(args)...);
}
C++:
class Solution {
public:
int combinationSum4(vector<int>& nums, int target) {
auto f = [&](auto& f, int i) -> uint32_t {
if (i == 0) return 1;
uint32_t res = 0;
for (int n : nums) if (i >= n) res += f(i - n);
return res;
};
return memoize(f, target);
}
};
- xài using Params = std::tuple<Args...>; thì nó chạy sai: https://rextester.com/QTC87092 với lvalue/const/volatile gì tùm lum
- xài perfect forwarding Args&& cho memoize thì gọi memoize(f, target) ko được vì f nhận int, mà perfect forwarding nó forward int& target
vì Params luôn là tuple<T1, T2, ... Tn> ko có ref/cv gì hết nên xài Args cho ròi, xài Args&& thì viết t1 + 0 t2 + 0 gì chắc
test thử bài unique path bữa trước: https://leetcode.com/submissions/detail/766251301/
Last edited: