6
\$\begingroup\$

Task:

Given an integer array of size N. Remove from the array all elements that occur less than three times and output the size of the resulting array and its contents.

My algorithm uses the following variables:

  • a - array of elements
  • N - size of array a
  • c - counter for counting matching
for (SHORT i = N - 1; i >= 0; i--)
{
   UCHAR c = 0;
   bool flag = false;

   for (SHORT j = N - 1; j >= 0 && c < 3 && !flag; j--)
   {
      c += a[i] == a[j];
      if (j > i)
         flag = a[i] == a[j];
   }

   if (c != 3 && !flag)
   {
      for (UCHAR j = i; j < N - 1; j++)
         a[j] = a[j + 1];
      N--;
   }
}

It works 100% accurately. I want to know your opinion about its complexity. Maybe there are some simpler options for checking the condition?

I need the most efficient algorithm. You can come up with many, this is one of the options.

\$\endgroup\$

1 Answer 1

11
\$\begingroup\$

The provided code has O(N^2) worst-case time complexity. You can use std::unordered_map to achieve O(N) complexity, which is optimal because reading the input takes O(n) time.

For future questions, I would suggest providing the entire program and some test cases. This makes it easier to understand the types of variables and provide suggestions that are useful.

Below is an implementation with std::unordered_map and testing / benchmarking.

#include <vector>
#include <unordered_map>
#include <iostream> // for printing
#include <cassert>  // for testing
#include <chrono>   // for benchmarking

using std::vector;
typedef std::chrono::high_resolution_clock::time_point time_point;

// provided code
vector<int> filter_triples1(const vector<int> &v)
{
    vector<int> a(v);
    int N = a.size();

    for (int i = N - 1; i >= 0; i--)
    {
        size_t c = 0;
        bool flag = false;

        for (int j = N - 1; j >= 0 && c < 3 && !flag; j--)
        {
            c += a[i] == a[j];
            if (j > i)
                flag = a[i] == a[j];
        }

        if (c != 3 && !flag)
        {
            for (int j = i; j < N - 1; j++)
                a[j] = a[j + 1];
            N--;
        }
    }

    a.resize(N);
    return a;
}

// returns a copy of v containing only the 
// elements that appear at least 3 times
vector<int> filter_triples2(const vector<int> &v)
{
    // counts[x] is the number of times x appears
    std::unordered_map<int, int> counts;

    for (const auto &x : v)
        ++counts[x];

    vector<int> result;

    for (const auto &x : v)
        if (counts[x] >= 3)
            result.push_back(x);

    return result;
}

// returns the time right now
time_point get_now()
{
    return std::chrono::high_resolution_clock::now();
}

int main()
{
    // testing
    vector<vector<int>> tests = {
        {},
        {1},
        {1, 1, 1},
        {1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3}
    };

    for (const auto &test : tests)
    {
        vector<int> answer1 = filter_triples1(test);
        vector<int> answer2 = filter_triples2(test);
        assert(answer1 == answer2);
    }

    // benchmarking
    vector<int> test;
    for (int i = 0; i < 100000; ++i)
        test.push_back(i);

    time_point start1 = get_now();
    vector<int> answer1 = filter_triples1(test);
    std::chrono::duration<double> diff1 = get_now() - start1;

    time_point start2 = get_now();
    vector<int> answer2 = filter_triples2(test);
    std::chrono::duration<double> diff2 = get_now() - start2;

    std::cout << "time1: " << diff1.count();
    std::cout << "\ntime2: " << diff2.count();
    assert(answer1 == answer2);

    return 0;
}

Here is the output:

time1: 40.8914
time2: 0.116645

This shows a >100x speedup for N = 100000.

\$\endgroup\$
2
  • \$\begingroup\$ The loop that populates result might just be a call to std::copy_if though that wouldn't necessarily be any cleaner. \$\endgroup\$ Commented Nov 19, 2024 at 20:20
  • \$\begingroup\$ Any particular reason to typedef std::chrono::high_resolution_clock::time_point time_point; vs. using std::chrono::high_resolution_clock::time_point;? \$\endgroup\$ Commented Nov 23, 2024 at 18:18

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.