The function must return the count of pairs of numbers in the array songs
(integer array consisting of lengths of songs in seconds) such that the pairs formed add up to whole minutes.
long playlist(int songs_count, int *songs) {
int i, j, k = 0;
for (i = 0; i < songs_count; i++) {
for (j = i + 1; j < songs_count; j++)
if ((songs[i] + songs[j]) % 60 == 0)
k++;
}
return k;
}
Putting all together. Continuing on the challenge to reduce the iterations on our algorithm, we have to perform the following steps: build the "index" with the information to be accessed later. iterate over the loop and fetch the additional information from the previously created "index"
As a result, the statements in the inner loop execute a total of N * M times. Thus, the complexity is O(N * M). In a common special case where the stopping condition of the inner loop is j < N instead of j < M (i.e., the inner loop also executes N times), the total complexity for the two loops is O(N2).
Since the complexity of printing the output would remain the same, all you can do is to "hide" the loops into existing methods that do what you want, not eliminate them, because the amount of work the system needs to perform remains the same in terms of the number of characters that need to be processed.
A first straight forward approach would be like this:
seconds%60
initialized to all zeroes.a = array[i]
songs and b = array[60-i]
matching songs which you need to combine: num = a*b; k += num;
i==0
and i==30
you need special handling as the matching song is in same array element: num = a*(a-1);
This will reduce the time complexity to O(N):
You need
n
to populate the array (could be done once when building the song list) and0..30
for the calculation.This results in O(N)+O(1)
Edit: Depending on your rules (does order of the songs matter) you might need to multiply with 2.
If the value of seconds is less, you can use hash map (unordered_map in c++) to solve it in ~O(n) complexity.
Suppose you know that the maximum value of the pair is 600 secs, then you can have another array storing these values.
for(int i = 1; i <= 10; i++)
{
a[i-1] = i * 60;
}
//a[] = {60, 120, 180, 240, 300, 360, 420, 480, 540, 600};
unordered_map <int, int> mymap;
for(int i = 0; i < songs_count; i++)
{
mymap[i] = songs[i];
}
Now you can modify your code as (Solution is for C++):
long playlist(int songs_count, int *songs)
{
int i, j, k = 0;
for(int i = 1; i <= 10; i++)
{
a[i-1] = i * 60;
}
//a[] = {60, 120, 180, 240, 300, 360, 420, 480, 540, 600};
unordered_map <int, int> mymap;
for(int i = 0; i < songs_count; i++)
{
mymap[i] = songs[i];
}
for (i = 0; i < songs_count; i++)
{
for (j = 0; j < n /*size of a*/; j++)
{
if (a[j] > songs[i] && mymap.find(a[j] - songs[i]) != mymap.end())
{
k++;
}
}
}
return k;
}
You can bring down the complexity from O(N2) to O(N) with a simple approach:
int a[60]
, for each i
in 0
..59
, compute the number of songs whose duration has i
seconds and a whole number of minutes. A single pass is sufficient.i
in the array, compute the number of pairs of songs of interest. again a single pass is needed.Assuming a pair must have different songs and order does not matter, here is an implementation:
long playlist(int songs_count, int *songs) {
long a[60] = { 0 };
int i;
long total;
for (i = 0; i < songs_count; i++)
a[songs[i] % 60]++;
total = (a[0] * (a[0] - 1) + a[30] * (a[30] - 1)) / 2;
for (i = 1; i <= 29; i++)
total += a[i] * a[60 - i];
return total;
}
If order matters and pairs can have twice the same song, the computation is different:
long playlist(int songs_count, int *songs) {
long a[60] = { 0 };
int i;
long total;
for (i = 0; i < songs_count; i++)
a[songs[i] % 60]++;
total = 0;
for (i = 0; i < 60; i++)
total += a[i] * a[(60 - i) % 60];
return total;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With