【问题标题】:Half the largest element in a vector and return the halfs n times向量中最大元素的一半并返回一半 n 次
【发布时间】:2022-01-20 06:56:12
【问题描述】:

给定的问题是: 给出了许多自然数“N”。半运算减去集合中最大的元素,将其分成两个相等的部分,然后将两个结果数返回给集合。任务是在半运算被应用“n”次时找到集合中的最大数。

输入格式

对于标准输入的每个例子都给出:“N”集合中数字的个数,以及元素的倍数“n”;

约束

0

输出: 分数或整数。

#include <cmath>
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <cassert>
using namespace std;
 
class Fraction{
    
public:
    Fraction(int t) : top(t), bottom(1) {}
    Fraction(int t, int b) : top(t), bottom(b)
    {
        normalize();
    }
    int numerator() const
    {  
        return top;
    }
 
    int denominator() const
    {
        return bottom;
    }
    int compare(const Fraction& right) const
    {
        return numerator() * right.denominator() - denominator() * right.numerator();
    }
private:
    void normalize()
{
    int sign = 1;
    if(top < 0)
    {
        sign = -1;
        top = -top;
    }
    if(bottom < 0)
    {
        sign = -1;
        bottom = -bottom;
    }
    assert(bottom != 0);
    int d = 1;
    if(top > 0) d = gcd(top, bottom);
    top = sign *(top / d);
    bottom = bottom / d;
}
    int gcd(int n, int m)
{
    assert(n > 0 && m > 0);
    while(n!=m)
    {
        if(n < m)
            m -= n;
        else
            n -= m;
    }
    return n;
}
    int top;
    int bottom;
};
 
Fraction operator/(const Fraction& left, const Fraction& right)
{
    Fraction result(left.numerator() * right.denominator(),
    left.denominator() * right.numerator());
    return result;
}
 
bool operator<(const Fraction& left, const Fraction& right)
{
    return left.compare(right) < 0;
}
ostream& operator<<(ostream& out, const Fraction& value)
{
    if(value.denominator() != 1)
        out << value.numerator() << "/" << value.denominator();
    else
        out << value.numerator();
    return out;
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
 
    int N,n;
    while(cin >> N && cin >> n)
    {
        vector<Fraction> vec;
        for(int i = 0; i < N; i++)
        {
            int value;
            cin >> value;
            vec.push_back(value);
        }
        for(int i = 0; i < n; i++)
        {        
            Fraction temp = *max_element(vec.begin(), vec.end()) / 2;
            int maxIndex = distance(vec.begin(), max_element(vec.begin(), vec.end()));
            vec[maxIndex] = temp;
            vec.push_back(temp);
        }
        cout << *max_element(vec.begin(), vec.end())<< endl;
    }
    
    return 0;
}

代码确实有效,但我的问题是由于hackerrank超时而终止 我也尝试过对其进行排序并处理最后一个元素,但它甚至比 max_element 还要慢。我正在寻找一种方法来优化我的代码或一种完全不同的方法的想法。

这里也是 make_heap 的实现,但它经历了 800 次迭代,它让我超时(应该能够处理 2000000)

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
 
    int N,n;
    while(cin >> N && cin >> n)
    {
        vector<Fraction> vec;
        for(int i = 0; i < N; i++)
        {
            int value;
            cin >> value;
            vec.push_back(value);
        }
        make_heap(vec.begin(),vec.end());
        for(int i = 0; i < n; i++)
        { 
            cout << "was here: " << i << endl;
            vec.push_back(vec.front() / 2); push_heap(vec.begin(),vec.end());
            vec.push_back(vec.front() / 2); push_heap(vec.begin(),vec.end());
            pop_heap(vec.begin(),vec.end()); vec.pop_back();
        }
        cout<< vec.front() << '\n';
    }
    
    return 0;
}

也用 priority_queue 尝试过,它也有 736 次迭代,然后由于超时而终止

int main() {
    int N,n;
    while(cin >> N && cin >> n)
    {
        priority_queue<Fraction> frac;
        for(int i = 0; i < N; i++)
        {
            int value;
            cin >> value;
            frac.push(value);
        }
        for(int i = 0; i < n; i++)
        { 
            Fraction temp = frac.top() / 2;
            frac.pop();
            frac.push(temp);
            frac.push(temp);
        }
        cout << frac.top() << endl;
    }
    return 0;
}

如果有人想知道这是解决方案:

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    
    int N,n;
    while(cin >> N && cin >> n)
    {
        vector<pair<Fraction, int>> vec;
        for(int i = 0; i < N; i++)
        {
            int value;
            cin >> value;
            vec.push_back(make_pair(value,1));
        }
        sort(vec.begin(),vec.end());
        while(vec.back().second <= n)
        {
            n -= vec.back().second;
            pair<Fraction,int> temp(vec.back().first / 2, vec.back().second * 2);
            vec.pop_back();
            vec.push_back(temp);
            sort(vec.begin(),vec.end());
        }
        cout << vec.back().first << endl;
    }
    
    return 0;
}

【问题讨论】:

  • 代码中没有任何可以加速的东西。如有疑问,请尝试排序。
  • 尝试排序在时间上是最糟糕的。
  • 这个想法不是每次都对数组进行完全排序。您可以尝试使用最大堆。
  • @Damien 我尝试使用 make_heap 但它经历了大约 763 次(应该能够进行 2000000 次)迭代,然后给了我超时,所以我想它也没有那么快。
  • 这是学习如何使用分析器的绝佳借口。找出瓶颈实际上在哪里。快速浏览一下,您无需每次迭代调用 max_element 两次。

标签: c++ algorithm


【解决方案1】:

你需要的技巧是你不需要列出所有的数字,你只需要有数量和数量。

这不是使用Fraction,而是使用std::pair&lt;Fraction, int&gt;。关键循环变成如下伪代码

    while (count of top element < n)
    {
        n -= count of top element
        temp = (value of top element / 2, count of top element * 2)
        remove top element
        push temp
    }

目前,在每个循环迭代中,您都会执行一个步骤并扩展您的数据结构。但是使用这种方法,每次循环迭代都会执行许多步骤,并且数据结构永远不会改变大小。

你最坏的情况是N = 100n = 2000000。然后你最终不得不遍历2000000 次循环,并拥有一个包含2000100 Fraction 对象的数据结构。

通过这项改进,您在前 100 次循环中执行 100 步,接下来的 100 次执行 200 步,接下来的 100 次执行 400 步,依此类推。结果,在 100k 循环中,您执行 (2^k-1) * 100 步。所以在 1500 次循环中,你已经完成了超过 200 万步,但你仍然只有 100 对数据。

【讨论】:

  • 天才,我一开始就有这个想法并尝试使用多图,但完全忘记了对。通过所有测试用例。感谢您的帮助
猜你喜欢
  • 2020-08-24
  • 1970-01-01
  • 2020-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-05
  • 2015-02-23
相关资源
最近更新 更多