Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
Given an array of integers and an integer x, I need to find the number of unordered triples in the array whose product is x. I have a brute-force O(n3) solution:
int solve(int a[], int n, int x) {
int ans = 0;
for (int i = 0; i < n; ++i)
for (int j = i+1; j < n; ++j)
for (int k = j+1; k < n; ++k)
if(a[i]*a[j]*a[k] == x)
ans++;
return ans;
}
Is there a faster way to do this, say in O(n log n) time?
You could
put all elements in a into a hashtable -- O(n)
Factorize x -- O(sqrt(x))
Build all possible triplets of divisors of x -- O(3^log(x))
Search for these triplets in your Hashtable -- O(1)
If a triplet exists, increase your counter -- O(1)
The runtime will now be dependent on the number of prime factors pf(x) of x, specifically O(3^pf(x)). Since the number of prime factors of x can be bounded by log(x) this yields O(3^log(x)) which could actually simplify further dependent on the exact base.
Code is in java but as you know, the idea remains the same.
Time complexity is O(n^1.5). I checked this with 10^5 elements and it works ok.
The idea is-
Put all elements of the list with their count in a map.
Now, if a[i]*a[j]*a[k] == x to be true, all these 3 have to be factors of x. Hence, if x%a[i] == 0, I hunt for checking all factors(pairs) that multiply to x/a[i] in sqrt(x/a[i]) time.
Since, we do it for every element in the list, complexity goes like this-
O(n) for adding elements to map.
O(n * n^0.5) for checking triplets.
So, total complexity = O(n) + O(n * n^0.5) = O(n^1.5) asymptotically.
ASSUMPTION - I am considering tuples as triplets having different indices in the array.
UPDATE - Current code considers different permutations of the same indices i,j,k as different tuples. You can fix it by having an additional map storing triplet indices as a string by joining them | (pipe) separated.
import java.util.*;
import java.io.*;
class Solution{
public static void main(String args[]) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
String[] s = br.readLine().split("\\s");
int[] a = new int[n];
for(int i=0;i<n;++i){
a[i] = Integer.parseInt(s[i]);
}
int x = Integer.parseInt(br.readLine());
System.out.println(solve(a,n,x));
}
private static long solve(int a[], int n, int x) {
long tuples = 0;
Map<Integer,Integer> elements = new HashMap<>();
for(int i=0;i<a.length;++i){
elements.put(a[i],elements.getOrDefault(a[i],0) + 1);
}
for(int i=0;i<a.length;++i){
if(x%a[i] == 0){
tuples += factorPairs(x/a[i],elements,a[i]);
}
}
return tuples;
}
private static long factorPairs(int x,Map<Integer,Integer> elements,int factor1){
long pairs = 0;
for(int i=1;i*i<=x;++i){
int second = i;
int third = x/i;
if(second*third == x && elements.containsKey(second) && elements.containsKey(third)){
long second_cnt = elements.get(second) - (second == factor1 ? 1 : 0);
long third_cnt = elements.get(third) - (third == factor1 ? 1 : 0);
pairs += second_cnt * third_cnt;
}
}
return pairs;
}
}
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I have an array y of dimension n, every dimension has m entries.
How do I iterate over all combinations of indices using nested for loops?
I'd like to get all possible combinations of sums like shown in this code:
for (int i = 0; i < m; ++i) {
for (int j = 0; j < m; ++j) {
...
for (int k = 0; k < m; ++k) {
z = x[0] + y[i]*x[1] + y[j]*x[2] + ... + y[k]*x[n];
}
}
}
If this is not possible using for loops, how else can it be achieved?
Here's a solution to the problem, probably not the optimal one, but illustrates the idea. Since you need to index y with as many indices at a time as there are y's, you need an array. The array's indices will be incremented each iteration, starting at the 0th index. When the 0th index reaches m, we carry over a 1, just like normal addition. When the integer at that next index reaches m, we carry over a 1 to the next index. When all of the indices went from 0 through m - 1, we know we're done. Test it in the browser if you wish.
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::vector<int> y = { 1, 2, 3 };
std::vector<int> x = { 0, 1, 2, 3 };
std::vector<int> indices = { 0, 0, 0 };
int m = y.size();
int sum = 0;
int index_to_increment_next = 0;
while (index_to_increment_next < m)
{
// sum up at current indices
sum += x[0];
for (int i = 0; i < m; i++)
{
sum += x[i + 1] * y[indices[i]];
}
int j;
for (j = 0; j < m; j++)
{
if (indices[j] < m - 1)
{
// increment indices
indices[j]++;
break;
}
// when the index reaches m, reset it to 0
// and try to increment the next one
indices[j] = 0;
}
// on the last iteration, this will be equal to m
// and all of the indices will be reset back to 0
index_to_increment_next = j;
}
std::cout << sum;
}
Update
I need a separate sum for every possible combination z = x[0] + y[i]*x[1] + y[j]*x[2] + ... + y[k]*x[n] where i,j,...k are n counters and take on values from 0 to m.
Just save the individual sums on each iteration and store them in e.g. a vector. See the code.
// declare above the while
std::vector<int> sums;
// ...
int sum = x[0];
for (int i = 0; i < m; i++)
{
sum += x[i + 1] * y[indices[i]];
}
sums.push_back(sum);
If I understand your problem correctly, then as Daniyal Shaikh said above in a comment
You can use recursion instead. it can prove to be a better alternate
An easy implementation of n for-loops is:
(n_counter and z are globals)
int n_counter = 0; // which is the 1,2,3 of your y[i]*x[**1**]
int z = x[0]; // all possible combinations of sums at every iteration
void recursion(int n, int m){
n_counter++;
for(int i=0 ; i<m ; i++){
z += y[i]*x[n_counter];
}
if(n_counter<=n){ // go deeper n times, which is equal to n for-loops
recursion(n, m);
}
return;
}
Every time we get deeper in the recursion, n_counter will increase because we need the number that increases.
For example with number 2: ".. + y[j]*x[2] + ..".
Lastly, all you have to do is to print z.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
Here is the link for the program: http://gpe.acm-icpc.tw/domjudge2/pct/showproblemtab.php?probid=10527&cid=5.
Here is the work I have done so far :
First, I created a function that will sort the array which is ord(a, j) in the code below.
The variable j is the size of the array that will increment every time the user input a number.
To compute the median, I have two cases.
1) if the size of the array is even, then I subtract the size of the array by 1 and divide it by 2, then the result will be the index of the sorted array plus the next element of the sorted array divided by 2 to find the median.
For example : an array of {1,3,6,2,7,8} elements. I will sort the array first which will give : {1,2,3,6,7,8} then the median will be (3+6)/2 = 4.
2) if the size of the array is odd, then I subtract the size of the sorted array by 1 and divide it by 2, the result is the index of the median.
For example : an array of {1,3,7,2,5} elements. I will sort the array first which will give : {1,2,3,5,7} then the median is 3.
int* ord(int A[], int n) // function to sort the array
{
for(int i = 0; i < n; i++)
{
for(int v = 0; v < n -1; v++)
{
if(A[v] > A[v+1])
{
swap(A[v], A[v+1]);
}
}
}
return A;
}
int main()
{
int a[N], x, j = 0, c;
while(cin >> x)
{
j++; // This is the size of the array
a[j-1]=x;
// Below is the algorithm for finding the median
if (j == 1) // if the array contains only one value, I just output the value
{
cout << a[0] << endl;
}
else // if it contains more than one value then I compute the median
{
ord(a, j); //sorted array
if (j % 2 == 0) // first case is when the size of the array is even
{
// First I subtract the size of the array by 1 and divide it by 2, then c will be the index of the sorted array plus the next element of the sorted array divided by 2 to find the median
c = (j-1) / 2;
cout << (a[c] + a[c+1]) / 2 << endl;
}
else // second case when the size of the array is odd
{
// First I subtract the size of the array by 1 and divide it by 2, c will be the index of the median
c = j-1;
cout << a[c / 2] << endl;
}
}
}
}
Use a std::vector to hold your ints. Then use std::sort on it. If you have to write your own sort, try to implement a quicksort or a mergsort.
This is a fast sort via a vector and std::sort.
int array_size = 8;
int myints[] = {32,71,12,45,26,80,53,33};
std::vector<int> myvector (myints, myints+array_size);
std::sort (myvector.begin(), myvector.end());
If you need to read up about faster sort algorithms:
https://en.wikipedia.org/wiki/Quicksort
https://en.wikipedia.org/wiki/Merge_sort
The general idea is to do some kind of presorting for parts of the array and then sort everything. This make the runtime log(n)n instead of nn. This is a major speed up, even more the bigger the numbers rise. Example:
log(1024)*1024 = 10*1024 = 10.240 Operations.
1024*1024 ~ 1.000.000 Operations <- 100 times slower
log(1.000.000)*1.000.000 = 20*1.000.000 = 20.000.000 Operations.
1.000.000*1.000.000 = 1.000.000.000.000 Operations <- 50.000 times slower
I think you are doing it wrong.
first of all you should not call the sorting function inside loop, it does the same work every time, and increasing time. It will be enough to call it once after the end of the while loop. This will drastically speed up your program.
Also inside while loop you have first incremented the value of j then you have assigned
a[j-1] = x;
you should first assign
a[j] = x;
and then j++;
because
a[j-1] = x; // here j-1 will take some fraction of milliseconds to calc [j-1].
Hope your program will speed up.
Given this question:
Given an array A on size N, you need to find the number of ordered
pairs (i, j) such that i < j and A[i] > A[j]
Input: First line contains one integer, N, size of array. Second line contains N space separated integers denoting the elements of the
array A.
Output: Print the number of ordered pairs (i, j) such that i < j and
A[i] > A[j].
Constraints:
1 ≤ N ≤ 10^6
1 ≤ A[i] ≤ 10^6
Source: hackerearth's merge sort tutorial
I'm encountering problems properly implementing the solution.
This is the code I wrote:
#include <iostream>
using namespace std;
int ar[10000000];
long long counting=0;
void merge(int* ALR, int* L, int left_length, int* R, int right_length) {
int l = 0;
int r = 0;
for (int i = 0; i < left_length + right_length;) {
if (l == left_length)ALR[i++] = R[r++];
else if (r == right_length)ALR[i++] = L[l++];
else if(L[l]>R[r]){
counting+=(left_length-l);
ALR[i++]=L[l++];
}
else ALR[i++]=R[r++];
}
}
void merge_sort(int* ALR, int length) {
if (length == 1)return;
int mid = length / 2;
int* L = new int[mid];
int* R = new int[length - mid];
int k = 0;
for (size_t i = 0; k < mid; i++)L[i] = ALR[k++];
for (size_t i = 0; k < length; i++)R[i] = ALR[k++];
merge_sort(L, mid);
merge_sort(R, length - mid);
merge(ALR, L, mid, R, length - mid);
delete(L);
delete(R);
}
int main() {
int t;
cin>> t;
for(int i=0;i<t;i++)cin>> ar[i];
merge_sort(ar, t);
cout<<counting;
return 0;
}
Now the problem is that I'm getting a wrong answer in the 2nd test case ...
The answer should be: 250194527312
The answer I get: 250002372570
Where did it go wrong?
A general principle you should follow is unit testing small bits of code. In this case, you should test the merge function, to see if what you get when you merges is correct. If you had written a test which merges two very small arrays, then you would have seen the result be in descending order, and the inversion count would usually be wrong.
Here's the test case I used for merge-sort inversion counting:
// expect 3 inversions in [1,3,5,2,4,6]
Your actual problem is an easy error to make (flip the comparitor and count the other branch as an inversion), and I guarantee many experienced programmers would make some equivalent mistake before running their tests. The difference between a novice and veteran is knowing how to find those mistakes (and structure tests so that they are found automatically).
I am pretty noobie with C++ and am trying to do some HackerRank challenges as a way to work on that.
Right now I am trying to solve Angry Children problem: https://www.hackerrank.com/challenges/angry-children
Basically, it asks to create a program that given a set of N integer, finds the smallest possible "unfairness" for a K-length subset of that set. Unfairness is defined as the difference between the max and min of a K-length subset.
The way I'm going about it now is to find all K-length subsets and calculate their unfairness, keeping track of the smallest unfairness.
I wrote the following C++ program that seems to the problem correctly:
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
int unfairness = -1;
int N, K, minc, maxc, ufair;
int *candies, *subset;
void check() {
ufair = 0;
minc = subset[0];
maxc = subset[0];
for (int i = 0; i < K; i++) {
minc = min(minc,subset[i]);
maxc = max(maxc, subset[i]);
}
ufair = maxc - minc;
if (ufair < unfairness || unfairness == -1) {
unfairness = ufair;
}
}
void process(int subsetSize, int nextIndex) {
if (subsetSize == K) {
check();
} else {
for (int j = nextIndex; j < N; j++) {
subset[subsetSize] = candies[j];
process(subsetSize + 1, j + 1);
}
}
}
int main() {
cin >> N >> K;
candies = new int[N];
subset = new int[K];
for (int i = 0; i < N; i++)
cin >> candies[i];
process(0, 0);
cout << unfairness << endl;
return 0;
}
The problem is that HackerRank requires the program to come up with a solution within 3 seconds and that my program takes longer than that to find the solution for 12/16 of the test cases. For example, one of the test cases has N = 50 and K = 8; the program takes 8 seconds to find the solution on my machine. What can I do to optimize my algorithm? I am not very experienced with C++.
All you have to do is to sort all the numbers in ascending order and then get minimal a[i + K - 1] - a[i] for all i from 0 to N - K inclusively.
That is true, because in optimal subset all numbers are located successively in sorted array.
One suggestion I'd give is to sort the integer list before selecting subsets. This will dramatically reduce the number of subsets you need to examine. In fact, you don't even need to create subsets, simply look at the elements at index i (starting at 0) and i+k, and the lowest difference for all elements at i and i+k [in valid bounds] is your answer. So now instead of n choose k subsets (factorial runtime I believe) you just have to look at ~n subsets (linear runtime) and sorting (nlogn) becomes your bottleneck in performance.
Let's say you have a number of unsorted arrays containing integers. Your job is to make sums of the arrays. The sums have to contain exactly one value from each array, i.e. (for 3 arrays)
sum = array1[2]+array2[12]+array3[4];
Goal: You should output the 20 combinations that generate the lowest possible sums.
The solution below is off-limits as the algorithm needs to be able to handle 10 arrays that can contain a huge number of integers. The following solution is way too slow for larger number of arrays:
//You already have int array1, array2 and array3
int top[20];
for(int i=0; i<20; i++)
top[i] = 1e99;
int sum = 0;
for(int i=0; i<array1.size(); i++) //One for loop per array is trouble for
for(int j=0; j<array2.size(); j++) //increasing numbers of arrays
for(int k=0; k<array3.size(); k++)
{
sum = array1[i] + array2[j] + array3[k];
if (sum < top[19])
swapFunction(sum, top); //Function that adds sum to top
//and sorts top in increasing order
}
printResults(top); // Outputs top 20 lowest sums in increasing order
What would you do to achieve correct results more efficiently (with a lower Big O notation)?
The answer can be found by considering how to find the absolute lowest sum, and how to find the 2nd lowest sum and so on.
As you only need 20 sums at most, you only need the lowest 20 values from each array at most. I would recommend using std::partial_sort for this.
The rest should be able to be accomplished with a priority_queue in which each element contains the current sum and the indicies of the arrays for this sum. Simply take each index of indicies and increase it by one, calculate the new sum and add that to the priority queue. The top most item of the queue should always be the one of the lowest sum. Remove the lowest sum, generate the next possibilities, and then repeat until you have enough answers.
Assuming that the number of answers needed is much less than Big O should be predominately be the efficiency of partial_sort (N + k*log(k)) * number of arrays
Here's some basic code to demonstrate the idea. There's very likely ways of improving on this. For example, I'm sure that with some work, you could avoid adding the same set of indicies multiple times, and there by eliminate the need for the do-while pop.
for (size_t i = 0; i < arrays.size(); i++)
{
auto b = arrays[i].begin();
partial_sort(b, b + numAnswers, arrays[i].end());
}
struct answer
{
answer(int s, vector<int> i)
: sum(s), indices(i)
{
}
int sum;
vector<int> indices;
bool operator <(const answer &o) const
{
return sum > o.sum;
}
};
auto getSum =[&arrays](const vector<int> &indices) {
auto retval = 0;
for (size_t i = 0; i < arrays.size(); i++)
{
retval += arrays[i][indices[i]];
}
return retval;
};
vector<int> initalIndices(arrays.size());
priority_queue<answer> q;
q.emplace(getSum(initalIndices), initalIndices );
for (auto i = 0; i < numAnswers; i++)
{
auto ans = q.top();
cout << ans.sum << endl;
do
{
q.pop();
} while (!q.empty() && q.top().indices == ans.indices);
for (size_t i = 0; i < ans.indices.size(); i++)
{
auto nextIndices = ans.indices;
nextIndices[i]++;
q.emplace(getSum(nextIndices), nextIndices);
}
}