简化分子和分母的最快方法

Posted

技术标签:

【中文标题】简化分子和分母的最快方法【英文标题】:Fastest way to simplify numerator and denominator 【发布时间】:2018-03-13 04:46:30 【问题描述】:

说,我有两个序列。其中一个可以是分子,第二个可以是分母。两个序列可能包含相同的变量。去除分子和分母中重复变量的最快算法是什么?

示例:初始序列。

A * B * C * D * O * V
---------------------
B * O * N * A * C

预期结果:A、B、C、O 应该消失了。

D * V
-----
N

我目前唯一的想法是创建两个数组并使用两个循环来查找和删除匹配的元素。也许有更好的解决方案?

【问题讨论】:

考虑查看一些标准库容器,例如std::set,它可以让您快速检查元素是否存在。这会给你一个 O(n log n) 算法。 数值:找到最大公约数(谷歌 GCD 算法)并通过将分子和分母都除以 GCD 来简化。还是象征性地问? 嗯,@FeiXiang 是正确的,我怀疑它有可能比O(n log n) 更快(还有std::unordered_setstd::unordered_multiset 你需要去掉两个集合的并集。 排序顶部和底部然后比较equal_ranges - 消除差异。 【参考方案1】:

你应该看看std::set_interaction,它可以用来确定两个排序集合中的公共数字。

例如

 std::vector< int > inter;
 std::set_intersection (numerator.begin ( ), numerator.end ( ), 
                        denominator.begin ( ), denominator.end ( ), 
                        std::back_inserter (inter));

现在删除分子中的常见数字:

 if (inter.size() != 0)
 
   std::vector<int> leftn;
   std::set_difference (numerator.begin ( ), numerator.end ( ), 
   inter.begin ( ), inter.end ( ), std::inserter (leftn, leftn.begin ( )));
   ...
 then do the same for denominator

但是我认为你应该首先确保你的分母和分子被分成质数,然后再尝试上述以获得最佳结果

例如

  2 * 4               4 
  -----  would yield ---   which obviously could be simplified more
  2 * 2               2

  2 * 2 * 2           2
  ---------   -->    ---
    2 *  2            1

但也许你已经这样做了。

编辑:排序集合

【讨论】:

需要注意的是,set_intersection 需要对源范围进行排序,其他集合操作也是如此。 “素数分割” - 假设项是常数,而不是变量。【参考方案2】:

这是我的解决方案,对分子和分母进行排序,然后比较相等的范围

std::vector<std::string> num = "A", "B", "C", "D", "O", "V";
std::vector<std::string> den = "B", "O", "N", "A", "C";

// sort to compare equal_ranges
std::sort(std::begin(num), std::end(num));
std::sort(std::begin(den), std::end(den));

decltype(std::equal_range(std::begin(num), std::end(num), "")) num_erstd::begin(num), std::begin(num);
decltype(std::equal_range(std::begin(den), std::end(den), "")) den_erstd::begin(den), std::begin(den);

while(num_er.second != std::end(num) && den_er.second != std::end(den))

    // next value to check (numerator or denominator?)
    auto v = num_er.second;
    if(*den_er.second < *v)
        v = den_er.second;

    // find the equal ranges
    num_er = std::equal_range(num_er.second, std::end(num), *v);
    den_er = std::equal_range(den_er.second, std::end(den), *v);

    // count the number of this value for num and den
    auto num_size = std::distance(num_er.first, num_er.second);
    auto den_size = std::distance(den_er.first, den_er.second);

    // erase from either num or den (or both)

    if(num_size >= den_size)
        num_er.second = num.erase(num_er.second - den_size, num_er.second);

    if(den_size >= num_size)
        den_er.second = den.erase(den_er.second - num_size, den_er.second);


for(auto const& s: num)
    std::cout << s << ' ';
std::cout << '\n';
std::cout << "-------------------" << '\n';
for(auto const& s: den)
    std::cout << s << ' ';
std::cout << '\n';

输出:

D V 
-------------------
N 

【讨论】:

以上是关于简化分子和分母的最快方法的主要内容,如果未能解决你的问题,请参考以下文章

java 如何把小数变成分数

怎么把小数化成分数的方法

各位大神速度帮我解答下好么,谢谢了,在线等,C++

如何在C中调用简化分数的函数?

Arcgis分子分母的标注

如何从小数中获取分子和分母?