【问题标题】:Converting JavaScript function to C++将 JavaScript 函数转换为 C++
【发布时间】:2021-06-05 11:53:18
【问题描述】:

我正在研究一个动态编程问题并且能够编写一个 Javascript 解决方案:

function howSum(targetSum,numbers,memo = {}){
    //if the targetSum key already in hashmap,return its value
    if(targetSum in memo) return memo[targetSum]; 

    if(targetSum == 0) return [];
    if(targetSum < 0) return null;

    for(let num of numbers){
        let aWay = howSum(targetSum-num,numbers,memo);
        if(aWay !== null){
            memo[targetSum] = [...aWay,num];
            return memo[targetSum];
        }
    }

    //no way to generate the targetSum using any elements of input array
    memo[targetSum] = null;
    return null;
}

现在我正在考虑如何将其转换为 CPP 代码。 对于memo 对象,我必须使用对unordered map 的引用。

但是我应该如何在基本条件中返回 empty array 和 null 值?我应该在插入元素时返回 array pointer 和 realloc 吗?那不是 C 方式编程呢? 另外我应该如何在 C++ 中将default parameter 传递给memo 无序映射?目前我已经重载了创建备忘录无序映射并传递其reference 的函数。

任何指导将不胜感激,因为我可以解决未来的问题。

【问题讨论】:

  • C++17 及更高版本通常具有用于此类情况的 std::optional 和 std::variant 模板。但是 C++ 不是 Javascript。看看这个整体逻辑:在 C++ 中 this 返回 null 的情况可能会通过抛出异常来指示致命错误来处理。就此而言,您无法真正将 Javascript 翻译成 C++,或将任何语言翻译成任何其他语言,一次只尝试一行。这总是以泪水告终。正确的做法是分析现有代码的作用,并在新语言中重新实现其整体逻辑。
  • 好的,谢谢你的洞察力。那么我应该去改变代码的逻辑吗?比如返回空数组和null?
  • 我相信我很清楚地表明这不是正确的方法。正确的方法是从逻辑上分析所示代码的作用,然后在 C++ 中实现与它在功能上逻辑等效的东西。在 C++ 中,NULL 常量只对指针类型有效,C++ 函数不能返回数组。 C++ 不能以这种方式工作。因此,您将需要为您的 C++ 代码找到这些概念的其他替代品,这是您需要自己做出的决定,因为只有您知道如何使用替代代码。
  • 你可以返回一个布尔值来表示成功,例如godbolt.org/z/6s6sb9e5r

标签: javascript c++ dynamic-programming


【解决方案1】:

这是我的看法:

#include <optional>
#include <vector>
#include <unordered_map>

using Nums = std::vector<int>;
using OptNums = std::optional<Nums>;

namespace detail {

using Memo = std::unordered_map<int, OptNum>>;

OptNums const & howSum(int targetSum, Nums const & numbers, Memo & memo) {
    if (auto iter = memo.find(targetSum); iter != memo.end()) {
        return iter->second; // elements are std::pair<int, OptNums>
    }
    auto & cached = memo[targetSum]; // create an empty optional in the map

    if (targetSum == 0) {
        cached.emplace(); // create an empty Nums in the optional
    }
    else if (targetSum > 0) {
        for (int num : numbers) {
            if (auto const & aWay = howSum(targetSum-num, numbers, memo)) {
                cached = aWay;           // copy vector into optional
                cached->push_back(num); 
            }
        }
    }
    return cached;
}
} // detail

std::optional<Nums> howSum(int targetSum, Nums const & numbers) {
    detail::Memo memo;
    return detail::howSum(targetSum, numbers, memo);
}

一些cmets:

  1. 使用两个函数,一个创建备忘录并将其传递给真正的实现函数是一个很好的模式。它使面向用户的界面变得干净。

  2. “detail”命名空间只是一个名字,没有什么神奇的含义,但经常用来表示实现细节。

  3. 在实现中,我将 references 返回到一个可选项。这是避免在算法从递归中展开的每次调用中复制返回向量的优化。然而,这确实需要一些小心,因为您必须小心返回对将超过本地范围的对象的引用(例如,没有返回 std::nullopt,或者引用绑定到临时可选。)这也是为什么我总是在备忘录对象中创建元素——即使在否定的情况下——所以我可以安全地返回对它的引用。注意,应用于 unordered_map 的 operator[] 将在元素不存在时创建该元素,而 find 不会。

  4. 由于detail函数返回的引用只有在调用者中声明的备忘录的生命周期,调用者本身必须返回一个它返回的可选的副本,以确保数据在清理过程中不被破坏的函数调用。请注意,它确实不返回引用。

  5. 另外,for 循环中的“if”也有一些问题。它声明一个本地引用,将其初始化为递归调用的结果。整个表达式是对 optional 的引用,它具有到 bool 的隐式转换,如果 optional 包含一个值,则为真。这是一个值得指出的有用习语,但更明确地说,这是等效的:

    if (auto const & aWay = howSum(targetSum-num, numbers, memo); aWay.has_value())

这是一个充实的示例,其中包含一些测试用例来证明它是有效的。 https://godbolt.org/z/cWrdhvM1n

【讨论】:

  • 谢谢你。从中学到很多东西!
【解决方案2】:

我也陷入了这个问题。我就是这样做的。

// howSum function
vector<int> howSum(int target, vector<int> numbers, unordered_map<int, vector<int>> &dp ){

    // base case 1 - for dp
    if(dp.find(target)!=dp.end()) return dp[target];

    // making a vector to return in the following base cases
    vector<int> res;

    // base case 2
    if(target == 0) {
        return res;
    }

    // base case 3
    if(target<0) {
        res.push_back(-1); // using -1 instead of NULL
        return res;
    }

    // the actual logic for the question
    for(int i=0;i<numbers.size();i++){
        int remainder = target - numbers[i];
        vector<int> result = howSum(remainder,numbers,dp); // recursion

        // if result vector doesn't contain -1, push target to result vector
        if(find(result.begin(),result.end(),-1)==result.end()){
            result.push_back(numbers[i]);
            dp.emplace(target,result);
            return result;
        }
    }
    res.push_back(-1);
    dp.emplace(target,res);
    return res;
}

// main function
int main(){

    vector<int>numbers = {20,50};
    unordered_map<int, vector<int>> dp;
    vector<int> res = howSum(300,numbers,dp);

    for(int i=0;i<res.size();i++){
        cout<<res[i]<<" ";
    }
    cout<<endl;
}

【讨论】:

    猜你喜欢
    • 2020-06-23
    • 1970-01-01
    • 2011-12-24
    • 2016-06-02
    • 2022-01-04
    • 2016-11-26
    • 2015-09-28
    • 1970-01-01
    相关资源
    最近更新 更多