Hi, I am struggling with a sorting problem - c++

The body of the problem is as follows:
Let n be a positive integer. Let v be an array with n positions counting from 1 to n and its elements being different numbers from 1 to n
Consider n being a power of 2(n = 2^m, with m being a positive integer) and array v has the property that for any i from 1 to m and any j from 1 to 2^(m-i), there is a k from 1 to 2^(m-i), so that on the positions in v from 2^i * (j-1)+1 to 2^i * j there are positive integers from 2^i * (k-1)+1 to 2^i * k, randomly. Write a program that sorts the array v in an ascending order, using for changing the order of the elements in v only the operation FLIP(n, v, 2^i * (j-1)+1, 2^i * j), with i from 1 to m and j from 1 to 2^(m-i), using the property of the array v.
The FLIP operation:
void FLIP(int v[], int n, int i, int j) {
while (i < j) {
int aux = v[i];
v[i] = v[j];
v[j] = aux;
i++;
j--;
}
}
Example of input:
n = 16
v = [14 13 15 16 11 12 9 10 2 1 4 3 8 7 6 5]
Output:
v = [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16]
What i found out is that if you group the elements in array v as follows:
2 by 2, the resulting groups have 2 consecutive values(14, 13),(15,16)
4 by 4, the resulting groups have 4 consecutive values(14,13,15,16)
2^i by 2^i, the resulting groups have 2^i consecutive values.
So my mind goes to a divide and conquer approach, but i don't know how to implement it.

Think I got it, I think so ... basically a modification of Merge sort, without merging, but instead using the FLIP function that was required to be used. Took me a while, I had an off by one error in there and it took me a minute.
#include <iostream>
using namespace std;
void FLIP(int v[], int n, int i, int j) {
while (i < j) {
int aux = v[i];
v[i] = v[j];
v[j] = aux;
i++;
j--;
}
}
void run(int v[], int n, int l, int r) {
if (n < 2) {
return;
}
if (v[l] > v[r - 1]) FLIP(v, n, l, r-1);
int m = (l + r) / 2;
run(v, n / 2, l, m);
run(v, n / 2, m, r);
}
int main(int argc, char** argv) {
int v[] = { 14,13,15,16,11,12,9,10,2,1,4,3,8,7,6,5 };
run(v, 16, 0, 16);
for (int& x : v) cout << x << ' ';
cout << endl;
}

Related

If NxM multiplication table put in order, what is number on K position?

If I have multiplication table 3x4
1 2 3 4
2 4 6 8
3 6 9 12
and put all these numbers in the order:
1 2 2 3 3 4 4 6 6 8 9 12
What number at the K position?
For example, if K = 5, then this is number 3.
N and M in the range 1 to 500 000. K is always less then N * M.
I've tried to use binary-search like in this(If an NxM multiplication table is put in order, what is number in the middle?) solution, but there some mistake if desired value not in the middle of sequence.
long findK(long n, long m, long k)
{
long min = 1;
long max = n * m;
long ans = 0;
long prev_sum = 0;
while (min <= max) {
ans = (min + max) / 2;
long sum = 0;
for (int i = 1; i <= m; i++)
{
sum += std::min(ans / i, n);
}
if (prev_sum + 1 == sum) break;
sum--;
if (sum < k) min = ans - 1;
else if (sum > k) max = ans + 1;
else break;
prev_sum = sum;
}
long sum = 0;
for (int i = 1; i <= m; i++)
sum += std::min((ans - 1) / i, n);
if (sum == k) return ans - 1;
else return ans;
}
For example, when N = 1000, M = 1000, K = 876543; expected value is 546970, but returned 546972.
I believe that the breakthrough will lie with counting the quantity of factorizations of each integer up to the desired point. For each integer prod, you need to count how many simple factorizations i*j there are with i <= m, j <= n. See the divisor functions.
You need to iterate prod until you reach the desired point, midpt = N*M / 2. Cumulatively subtract σ0(prod) from midpt until you reach 0. Note that once prod passes min(i, j), you need to start cropping the divisor count, due to running off the edge of the multiplication table.
Is that enough to get you started?
Code of third method from this(https://leetcode.com/articles/kth-smallest-number-in-multiplication-table/#) site solve the problem.
bool enough(int x, int m, int n, int k) {
int count = 0;
for (int i = 1; i <= m; i++) {
count += std::min(x / i, n);
}
return count >= k;
}
int findK(int m, int n, int k) {
int lo = 1, hi = m * n;
while (lo < hi) {
int mi = lo + (hi - lo) / 2;
if (!enough(mi, m, n, k)) lo = mi + 1;
else hi = mi;
}
return lo;
}

Play With Numbers Programming Challenge (mean value of subarrays)

I'm trying to solve this Play with Numbers problem in Hackerearth. I have passed the test cases but, I kept getting time limit exceeded. Can someone help me improve its performance in order to pass the time limit, please?
This is my code -
#include <iostream>
using namespace std;
int main()
{
int n, q, i, l, r, j, sum;
cin >> n >> q;
int *arr = new int[n];
for (i = 0; i < n; i++)
{
cin >> arr[i];
}
for (i = 0; i < q; i++)
{
sum = 0;
cin >> l >> r;
for (j = l - 1; j <= r - 1; j++)
{
sum += arr[j];
}
cout << sum / (r - l + 1) << endl;
}
delete[] arr;
}
You have to remove the inner loop. Instead of storing the elements in the array, store the cumulative sum.
E. g. the elements are 1, 2 ,2, 1, 4.
You have to store 1, (1 + 2 =) 3, (1 + 2 + 2 =) 5, (1 + 2 + 2 + 1 =)6, (1 + 2 + 2 + 1 + 4 =) 10. Then you can calculate the sum of subarray with last_element - first_element.
E. g. for start index 2 and end index = 5 you get 2 + 2 + 1 + 4 = 10 - 1.
You don't need the inner loop.

I can't figure out a sum and numbers solution

I am not that skilled or advanced in C++ and I have trouble solving a problem.
I know how to do it mathematically but I can't write the source code, my algorithm is wrong and messy.
So, the problem is that I have to write a code that reads a number ( n ) from the keyboard and then it has to find a sum that is equal to n squared ( n ^ 2 ) and the number of sum's elements has to be equal to n.
For example 3^2 = 9, 3^2 = 2 + 3 + 4, 3 elements and 3^2 is 9 = 2 + 3 + 4.
I had several attempts but none of them were successful.
I know I'm borderline stupid but at least I tried.
If anyone has the time to look over this problem and is willing to help me I'd be very thankful.
1
#include <iostream>
#include <list>
#include <algorithm>
using namespace std;
int main()
{
//1,3,5,7,9,11,13,15,17,19,21,23,25,27..
int n;
list<int> l;
cin >> n;
if ( n % 2 == 0 ){
cout << "Wrong." << endl;
}
for ( int i = 1; i <= 99;i+=2){
l.push_back(i);
}
//List is full with 1,3,5,7,9,11,13,15,17,19,21,23,25,27..
list<int>::iterator it = find(begin(l),end(l), n);
}
2
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int main()
{
// 3^2 = 2 + 3 + 4
// 7^2 = 4 + 5 + 6 + 7 + 8 + 9 + 10
int n;
int numbers[100];
for (int i = 0; i <= 100; i++){
numbers[i] = i;
}
cin >> n;
int requiredSum;
requiredSum = n * n;
//while(sum < requiredSum){
// for(int i = 1; i < requiredSum; i++){
// sum += i;
// sumnums.push_back(sum);
// }
//}
int sum = 0;
std::vector<int> sumnums;
while(sum < requiredSum){
for(int i = 1; i < requiredSum; i++){
sum += i;
sumnums.push_back(sum);
}
}
for(int i=0; i<sumnums.size(); ++i)
std::cout << sumnums[i] << ' ';
}
Update:
The numbers of the sum have to be consecutive numbers.Like 3 * 3 has to be equal to 2 + 3 + 4 not 3 + 3 + 3.
So, my first try was that I found a rule for each sum.
Like 3 * 3 = 2 + 3 + 4, 5 * 5 = 3 + 4 + 5 + 6 + 7, 7 * 7 = 4 + 5 + 6 + 7 + 8 + 9 + 10.
Every sum starts with the second element of the previous sum and continues for a number of elements equal to n - 1, like 3 * 3 = 2 + 3 + 4, 5 * 5 , the sum for 5 * 5 starts with 3 + another 4 elements.
And another algorithm would be #molbdnilo 's, like 3 * 3 = 3 + 3 + 3 = 3 + 3 + 3 - 1 + 1, 3 * 3 = ( 3 - 1 ) + 3 + ( 3 + 1 ), but then 5 * 5 = (5 - 2) + ( 5 - 1 ) + 5 + 5 + 1 + 5 + 2
Let's do a few special cases by hand.
(The division here is integer division.)
3^2: 9
2 + 3 + 4 = 9
x-1 x x+1
1 is 3/2
5: 25
3 + 4 + 5 + 6 + 7 = 25
x-2 x-1 x x+1 x+2
2 is 5/2
7: 49
4 + 5 + 6 + 7 + 8 + 9 + 10
x-3 x-2 x-1 x x+1 x+2 x+3
3 is 7/2
It appears that we're looking for the sequence from n - n / 2 to n + n / 2.
(Or, equivalently, n / 2 + 1 to n / 2 + n, but I like symmetry.)
Assuming that this is correct (the proof left as an exercise ;-):
int main()
{
int n = 0;
std::cin >> n;
if (n % 2 == 0)
{
std::cout << "Must be odd\n";
return -1;
}
int delta = n / 2;
for (int i = n - delta; i <= n + delta; i++)
{
std::cout << i << " ";
}
std::cout << std::endl;
}
If there is not constraints on what are the elements forming the sum, the simplest solution is just to sum up the number n, n times, which is always n^2.
int main()
{
int n;
cout<<"Enter n: ";
cin >> n;
for(int i=0; i<n-1; i++){
cout<<n<<"+";
}
cout<<n<<"="<<(n*n);
return 0;
}
Firstly, better use std::vector<> than std::list<>, at least while you have less than ~million elements (it will be faster, because of inside structure of the containers).
Secondly, prefer ++i usage, instead of, i++. Specially in situation like that
...for(int i = 1; i < requiredSum; i++)...
Take a look over here
Finally,
the only error you had that you were simply pushing new numbers inside container (std::list, std::vector, etc.) instead of summing them, so
while(sum < requiredSum){
for(int i = 1; i < requiredSum; i++){
sum += i;
sumnums.push_back(sum);
}
change to
// will count our numbers
amountOfNumbers = 1;
while(sum < requiredSum && amountOfNumber < n)
{
sum += amountOfNumbers;
++amountOfNumbers;
}
// we should make -1 to our amount
--amountOfNumber;
// now let's check our requirements...
if(sum == requiredSum && amountOfNumbers == n)
{
cout << "Got it!";
// you can easily cout them, if you wish, because you have amountOfNumbers.
// implementation of that I am leaving for you, because it is not hard ;)
}
else
{
cout << "Damn it!;
}
I assumed that you need sequential sum of numbers that starts from 1 and equals to n*n and their amount equils to n.
If something wrong or need explanation, please, do not hesitate to contact me.
Upd. amountOfNumber < n intead <=
Also, regarding "not starting from 1". You said that you know how do it on paper, than could you provide your algorithm, then we can better understand your problem.
Upd.#2: Correct and simple answer.
Sorry for such a long answer. I came up with a great and simple solution.
Your condition requires this equation x+(x+1)+(x+2)+... = n*n to be true then we can easily find a solution.
nx+ArPrg = nn, where is
ArPrg - Arithmetic progression (ArPrg = ((n-1)*(1+n-1))/2)
After some manipulation with only unknown variable x, our final equation will be
#include <iostream>
int main()
{
int n;
std::cout << "Enter x: ";
std::cin >> n;
auto squareOfN = n * n;
if (n % 2 == 0)
{
std::cout << "Can't count this.\n";
}
auto x = n - (n - 1) / 2;
std::cout << "Our numbers: ";
for (int i = 0; i < n; ++i)
std::cout << x + i << " ";
return 0;
}
Math is cool :)

Sum of 4 integers in 4 arrays

Given four lists A, B, C, D of integer values, compute how many tuples (i, j, k, l) there are such that A[i] + B[j] + C[k] + D[l] is zero.
To make problem a bit easier, all A, B, C, D have same length of N where 0 ≤ N ≤ 500. All integers are in the range of -228 to 228 - 1 and the result is guaranteed to be at most 231 - 1.
Example:
Input:
A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]
Output:
2
Explanation:
The two tuples are:
1. (0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0
I just came up with a solution that concatenates all the vectors and find the 4 sum. But I know there is a better solution. Would someone explain a better solution ? I just see codes using O(N^2) but I can't understand it.
This was my O(n^2) solution:
int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
int n = A.size();
int result = 0;
unordered_map<int,int> sumMap1;
unordered_map<int,int> sumMap2;
for(int i = 0; i < n; ++i) {
for(int j = 0; j < n; ++j) {
int sum1 = A[i] + B[j];
int sum2 = C[i] + D[j];
sumMap1[sum1]++;
sumMap2[sum2]++;
}
}
for(auto num1 : sumMap1) {
int number = num1.first;
if(sumMap2.find(-1 * number) != sumMap2.end()) {
result += num1.second * sumMap2[-1 * number];
}
}
return result;
}
The core observation is - if W + X + Y + Z = 0 then W + X = -(Y + Z).
Here I used two hash-tables for each of possible sums in both (A, B) and (C, D) find number of occurrences of this sum.
Then, for each sum(A, B) we can find if sum(C, D) contains complimentary sum which will ensure sum(A, B) + sum(C, D) = 0. Add (the number of occurrences of sum(a, b)) * (number of occurrences of complimentary sum(c,d)) to the result.
Creating sum(A, B) and sum(C, D) will take O(n^2) time. And counting the number of tuples is O(n^2) as there are n^2 sum for each pairs(A-B, C-D). Other operation like insertion and search on hashtable is amortized O(1). So, the overall time complexity is O(n^2).

matrix multiplication as column major

I am trying to multiply as column major and I can't seem to find the right formula!
I want to have the matrices as 1D.
Let's say I have these matrices:
A=
1 3
2 4
and B=
5 2 1
6 3 7
The above matrices are assumed that are stored already in column major order.
I am trying:
int main(int argc, const char* argv[]) {
int rows=2;
int cols=3;
int A[rows*rows];
int B[rows*cols];
int res[rows*cols];
A[0]=1;
A[1]=3;
A[2]=2;
A[3]=4;
B[0]=5;
B[1]=2;
B[2]=1;
B[3]=6;
B[4]=3;
B[5]=7;
/*A[0]=1;
A[1]=2;
A[2]=3;
A[3]=4;
B[0]=5;
B[1]=6;
B[2]=2;
B[3]=3;
B[4]=1;
B[5]=7;
*/
//multiplication as column major
for (int i=0;i<rows;i++){
for (int j=0;j<cols;j++){
res[i+j*rows]=0;
for (int k=0;k<rows;k++){
res[i+j*rows]+=A[i+k*rows]*B[k+j*cols];
}
}
}
for (int i=0;i<rows*cols;i++){
printf("\n\nB[%d]=%d\t",i,res[i]);
}
return 0;
}
I am not getting the correct results.
Also,I can't understand (in the case where the matrices are stored in column major already) ,how to index the matrices A and B.
A[0]=1;
A[1]=3;
...
or
A[0]=1;
A[1]=2;
...
I don't want to transpose the matrices and then use row major.
I want to handle the data as column major.
Because the indices ,if stored as column major,will be different (hence,will matter in order to do the multiplication).
There are two things that lead to your confusion here.
First, the data in your contiguous one-dimensional vector is not in column-major order as you say, but in row-major order, as is the usual layout of two-dimensional contiguous arrays in C. The linear one-dimensional indices of row i and column j in a matrix with M rows and N columns (MxN) are:
A[i*N + j] // row major
A[i + M*j] // column major
The "major" refers to the dimension of the outer loop when traversing the array sequentially with two nested loops:
n = 0;
for (i = 0; i < M; i++) {
for (j = 0; j < N; j++) {
printf("%8d", A[n++]);
}
printf("\n");
}
Second, you use the two dimensions rows and columns which are the dimensions of the resulting matrix, which is confusing, because the number of columns in A is rows.
In fact, there are three different dimensions involved in matrix multiplication when you multiply an MxL matrix A with an LxN matrix B to get an MxN matrix C. In your case, M and L happen to be both 2:
L (k) | N (j)
|
| 5 2 1
L (k) |
| 6 3 7
|
-----------------+-------------
|
1 3 | 23 11 22
M (i) |
2 4 | 34 16 30
|
The letters in parentheses are the variables the code below uses to iterate over the respective dimension.
Now you can multiply your matrices in row-major format:
#define M 2
#define N 3
#define L 2
int A[M * L] = {1, 3, 2, 4};
int B[L * N] = {5, 2, 1, 6, 3, 7};
int res[M * N];
int i, j, k;
for (i = 0; i < M; i++) {
for (j = 0; j < N; j++) {
res[j + i * N] = 0;
for (k = 0; k < L; k++) {
res[j + i * N] += A[k + i * L] * B[j + k * N];
}
}
}
for (i = 0; i < M * N; i++) printf("[%d] = %d\n", i, res[i]);
or in column-major format:
#define M 2
#define N 3
#define L 2
int A[M * L] = {1, 2, 3, 4};
int B[L * N] = {5, 6, 2, 3, 1, 7};
int res[M * N];
int i, j, k;
for (i = 0; i < M; i++) {
for (j = 0; j < N; j++) {
res[j * M + i] = 0;
for (k = 0; k < L; k++) {
res[j * M + i] += A[k * M + i] * B[j * L + k];
}
}
}
for (i = 0; i < M * N; i++) printf("[%d] = %d\n", i, res[i]);
Both input and output are in the respective matrix representation and differ in the two cases, of course.
What do you think about
res[i+j*rows]+=A[i+k*rows]*B[k+j*cols];
what it will do?
It will access array res, A and B out of bound when i and k becomes 1 and j becomes 2.
res[1+2*2]+=A[1+1*2]*B[1+2*3] = res[5]+=A[4]*B[7];
This will invoke undefined behavior and you may get either expected or unexpected result.
I think you need this:
res[i*rows+j] += A[i*rows + k] * B[j + k*cols];