Merge sort: time limit exceed - c++14

Why I am getting time limit exceeded error in sorting array using merge sort algorithm? What is wrong with my code? I have taken an input of 9 elements.
Input: 4 2 1 8 5 9 6 7 0
Output: Time limit exceeded
#include <bits/stdc++.h>
using namespace std;
int a[100];
void merge(int a[], int l, int r, int m) {
int t[r - l + 1];
int i = l, j = m + 1, k = 0;
while (i <= m && j <= r) {
if (a[i] < a[j])
t[k++] = a[i++];
else
t[k++] = a[j++];
}
while (i <= m)
t[k++] = a[i++];
while (j <= r)
t[k++] = a[j++];
for (int i = l; i <= r; i++)
a[i] = t[i - l];
}
void msort(int a[], int l, int r) {
if (l > r)
return;
int m = (r + l) / 2;
msort(a, l, m);
msort(a, m + 1, r);
merge(a, l, r, m);
}
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++)
cin >> a[i];
msort(a, 0, n - 1);
for (int i = 0; i < n; i++)
cout << a[i] << " ";
cout << endl;
return 0;
}

There are some problems in your code:
The test for termination in msort() is incorrect: you should stop when the slice has a single element or less. You currently loop forever on slices of 1 element.
if (l >= r) return;
You should test in main() if the number n of elements read from the user is no greater than 100, the size of the global array a into which you read the elements to be sorted. You should instead use a local array with the proper size or allocate the array from the heap. The temporary array t in merge() might also be too large for automatic allocation. It is more efficient to allocate temporary space once and pass it recursively.
Note also that it is idiomatic in C and C++ to specify array slices with the index of the first element and the index of the element after the last one. This simplifies the code and allows for empty arrays and avoid special cases for unsigned index types.
Here is a modified version with this approach:
#include <bits/stdc++.h>
using namespace std;
void merge(int a[], int l, int r, int m, int t[]) {
int i = l, j = m, k = 0;
while (i < m && j < r) {
if (a[i] < a[j])
t[k++] = a[i++];
else
t[k++] = a[j++];
}
while (i < m)
t[k++] = a[i++];
while (j < r)
t[k++] = a[j++];
for (int i = l; i < r; i++)
a[i] = t[i - l];
}
void msort(int a[], int l, int r, int t[]) {
if (r - l > 1) {
int m = l + (r - l) / 2;
msort(a, l, m, t);
msort(a, m, r, t);
merge(a, l, r, m, t);
}
}
void msort(int a[], int n) {
if (n > 1) {
int *t = new int[n];
msort(a, 0, n, t);
delete[] t;
}
}
int main() {
int n;
cin >> n;
if (n <= 0)
return 1;
int *a = new int[n];
for (int i = 0; i < n; i++)
cin >> a[i];
msort(a, n);
for (int i = 0; i < n; i++)
cout << a[i] << " ";
cout << endl;
delete[] a;
return 0;
}

Related

Runtime error for large inputs for sorting ( quicksort)

This is a very simple program where the user inputs (x,y) coordinates and distance 'd' and the program has to find out the number of unrepeated coordinates from (x,y) to (x+d,y).
For eg: if input for one test case is: 4,9,2 then the unrepeated coordinates are (4,9),(5,9) and (6,9)(x=4,y=9,d=2). I have used a sorting algorithm as mentioned in the question (to keep track of multiple occurrences) however the program shows runtime error for test cases beyond 30. Is there any mistake in the code or is it an issue with my compiler?
For a detailed explanation of question: https://www.hackerearth.com/practice/algorithms/sorting/merge-sort/practice-problems/algorithm/missing-soldiers-december-easy-easy/
#include <stdio.h>
#include <stdlib.h>
int partition(int *arr, int p, int r) {
int x;
x = arr[r];
int tmp;
int i = p - 1;
for (int j = p; j <= r - 1; ++j) {
if (arr[j] <= x) {
i = i + 1;
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
tmp = arr[i + 1];
arr[i + 1] = arr[r];
arr[r] = tmp;
return (i + 1);
}
void quicksort(int *arr, int p, int r) {
int q;
if (p < r) {
q = partition(arr, p, r);
quicksort(arr, p, q - 1);
quicksort(arr, q + 1, r);
}
}
int count(int A[],int ct) {
int cnt = 0;
for (int i = 0; i < ct; ++i) {
if (A[i] != A[i + 1]) {
cnt++;
}
}
return cnt;
}
int main() {
int t;
scanf("%d", &t);
long int tmp, y, d;
int ct = 0;
int i = 0;
int x[1000];
int j = 0;
for (int l = 0; l < t; ++l) {
scanf("%d%d%d", &tmp, &y, &d);
ct = ct + d + 1; //this counts the total no of coordinates for each (x,y,d)
for (int i = 0; i <= d; ++i) {
x[j] = tmp + i; //storing all possible the x and x+d coordinates
j++;
}
}
int cnt;
int p = ct - 1;
quicksort(x, 0, p); //quicksort sorting
for (int l = 0; l < ct; ++l) {
printf("%d ", x[l]); //prints sorted array not necessary to question
}
cnt = count(x, ct); //counts the number of non-repeated vertices
printf("%d\n", cnt);
}
The problem was the bounds of the array int x[1000] is not enough for the data given below.

Find the number of intersections of n line segments with endpoints on two parallel lines

Finding the number of intersections of n line segments with endpoints on two parallel lines.
Let there be two sets of n points:
A={p1,p2,…,pn} on y=0
B={q1,q2,…,qn} on y=1
Each point pi is connected to its corresponding point qi to form a line segment.
I need to write a code using divide-and-conquer algorithm which returns the number of intersection points of all n line segments.
for example:
input:
3
1 101
-234 234
567 765
output:
1
I coded as below but it I have wrong answers.
can anyone help me with this code or give me another solution for the question?
#include<iostream>
#include <vector>
#include<algorithm>
using namespace std;
void merge1(vector< pair <int, int> > vect, int l, int m, int r)
{
int n1 = m - l + 1;
int n2 = r - m;
vector< pair <int, int> > vect_c_l(n1);
vector< pair <int, int> > vect_c_r(n2);
for (int i = 0; i < n1; i++)
vect_c_l[i] = vect[l + i];
for (int j = 0; j < n2; j++)
vect_c_r[j] = vect[m + 1 + j];
int i = 0;
int j = 0;
int k = l;
while (i < n1 && j < n2) {
if (vect_c_l[i].first <= vect_c_r[j].first) {
vect[k] = vect_c_l[i];
i++;
}
else {
vect[k] = vect_c_r[j];
j++;
}
k++;
}
while (i < n1) {
vect[k] = vect_c_l[i];
i++;
k++;
}
while (j < n2) {
vect[k] = vect_c_r[j];
j++;
k++;
}
}
int merge2(vector< pair <int, int> > vect, int l, int m, int r)
{
int n1 = m - l + 1;
int n2 = r - m;
int inv_count = 0;
vector< pair <int, int> > vect_c_l(n1);
vector< pair <int, int> > vect_c_r(n2);
for (int i = 0; i < n1; i++)
vect_c_l[i] = vect[l + i];
for (int j = 0; j < n2; j++)
vect_c_r[j] = vect[m + 1 + j];
int i = 0;
int j = 0;
int k = l;
while (i < n1 && j < n2) {
if (vect_c_l[i].second < vect_c_r[j].second) {
vect[k] = vect_c_l[i];
i++;
}
else {
vect[k] = vect_c_r[j];
j++;
inv_count = inv_count + (m - i);
}
k++;
}
while (i < n1) {
vect[k] = vect_c_l[i];
i++;
k++;
}
while (j < n2) {
vect[k] = vect_c_r[j];
j++;
k++;
}
return inv_count;
}
void mergeSort1(vector< pair <int, int> > vect, int l, int r) {
if (l >= r) {
return;
}
int m = l + (r - l) / 2;
mergeSort1(vect, l, m);
mergeSort1(vect, m + 1, r);
merge1(vect, l, m, r);
}
int mergeSort2(vector< pair <int, int> > vect, int l, int r) {
int inv_count = 0;
if (r > l) {
int m = l + (r - l) / 2;
inv_count += mergeSort2(vect, l, m);
inv_count += mergeSort2(vect, m+ 1, r);
/*Merge the two parts*/
inv_count += merge2(vect, l, m + 1, r);
}
return inv_count;
}
int main() {
int n,c=0;
cin >> n;
int a, b;
vector< pair <int, int> > vect;
for (int i = 0;i < n;i++) {
cin >> a >> b;
vect.push_back(make_pair(a, b));
}
mergeSort1(vect,0,n-1);
cout << mergeSort2(vect,0, n - 1);
}
I'd take advantage of the idea that computing whether the segments intersect is much simpler than computing where they intersect. Two segments intersect if their x values are on different sides of one another on y=1 and y=0. (i.e. if both x values on one segment are both smaller than the others, or both larger).
Objects make this easy to state. Build a segment object who's main job is to determine whether it intersects another instance.
class Segment {
constructor(x) {
this.x0 = x[0];
this.x1 = x[1];
}
// answer whether the reciever intersects the passed segment
intersects(segment) {
// this is ambiguous in the problem, but assume touching endpoints
// count as intersections
if (this.x0 === segment.x0 || this.x1 === segment.x1) return true;
let sort0 = this.x0 < segment.x0
let sort1 = this.x1 < segment.x1
return sort0 !== sort1
}
}
let input = [
[1, 101],
[-234, 234],
[567, 765]
];
let segments = input.map(x => new Segment(x))
// check segments with one another in pairs
let pairs = segments.map((v, i) => segments.slice(i + 1).map(w => [v, w])).flat();
let intersections = pairs.reduce((acc, p) => p[0].intersects(p[1]) ? acc + 1 : acc, 0)
console.log(intersections)
You can also see the problem by abstracting from all the lines.
If there were no intersection that would mean that the order of indexes on both parallel lines are the same.
So the number of intersections are equal to the number of swaps you need to perform on neughbor -points to get the same order of indexes on both sides
In your example you have the two sequences of indexes
1,3,4,2 on the upper line
2,1,4,3 on the lower line
to convert the lower sequence by swapping neighbours, you need 4 swaps:
2,1,4,3 start
-> 1,2,4,3
-> 1,4,2,3
-> 1,4,3,2
-> 1,3,4,2 = upper sequence

Please spot the error in this merge sort code

I have provided the code for sorting an array using the merge sort algorithm, I'm unable to find the error, this code is not giving the correctly sorted array as it's output. The function mergesort is called recursively to divide the array till its size is reduced to 1. Then multiple arrays are merged using the merge function.
#include <bits/stdc++.h>
using namespace std;
void merge(int a[], int m, int l, int h) {
int n1 = m - l + 1, n2 = h - m;
int t1[n1], t2[n2];
for (int i = 0; i < n1; i++) {
t1[i] = a[i + l];
}
for (int i = 0; i < n2; i++) {
t2[i] = a[i + m + 1];
}
int k = 0, p = 0, r = 0;
while (k < n1 && p < n2) {
if (t1[k] <= t2[p]) {
a[r] = t1[k];
k++;
r++;
} else {
a[r] = t2[p];
p++;
r++;
}
}
while (k < n1) {
a[r] = t1[k];
k++;
r++;
}
while (p < n2) {
a[r] = t2[p];
p++;
r++;
}
}
void mergesort(int a[], int l, int h) {
if (l < h) {
int m = l + (h - l) / 2;
mergesort(a, l, m);
mergesort(a, m + 1, h);
merge(a, m, l, h);
}
}
int main() {
int a[5] = { 1, 2, 3, 4, 5 };
mergesort(a, 0, 4);
for (int i = 0; i < 5; i++) {
cout << a[i] << " ";
}
return 0;
}
The bug in the merge function is r should be initialized to l, not 0. You are not merging the slices into the original position.
Also note that the last loop while (p < n2) in this function is redundant: the remaining elements in the right slice are already in the proper place in the original array.
Here is a modified version:
void merge(int a[], int m, int l, int h) {
int n1 = m - l + 1, n2 = h - m;
int t1[n1], t2[n2];
for (int i = 0; i < n1; i++) {
t1[i] = a[i + l];
}
for (int i = 0; i < n2; i++) {
t2[i] = a[i + m + 1];
}
int k = 0, p = 0, r = l;
while (k < n1 && p < n2) {
if (t1[k] <= t2[p]) {
a[r] = t1[k];
k++;
r++;
} else {
a[r] = t2[p];
p++;
r++;
}
}
while (k < n1) {
a[r] = t1[k];
k++;
r++;
}
}
To further simplify the code, here are some more remarks:
it is less confusing to make use the convention that h be the first index beyond the end of the slice. This way the initial call uses the array length and mergesort can compute the slice length as h - l.
variable name l looks confusingly close to number 1.
the arguments to merge are usually in the order l, m, h, and m is the index of the start of the right slice.
the right slice does not need saving.
using variable length arrays with automatic storage t1[n2] may cause a stack overflow for large arrays.
Here is a modified version:
#include <bits/stdc++.h>
using namespace std;
void merge(int a[], int lo, int m, int hi) {
int i, j, k;
int n1 = m - lo;
int t1[n1];
for (i = 0; i < n1; i++) {
t1[i] = a[lo + i];
}
i = 0;
j = m;
k = lo;
while (i < n1 && j < hi) {
if (t1[i] <= a[j]) {
a[k++] = t1[i++];
} else {
a[k++] = a[j++];
}
}
while (i < n1) {
a[k++] = t1[i++];
}
}
void mergesort(int a[], int lo, int hi) {
if (hi - lo >= 2) {
int m = lo + (hi - lo) / 2;
mergesort(a, lo, m);
mergesort(a, m, hi);
merge(a, lo, m, hi);
}
}
int main() {
int a[5] = { 1, 5, 2, 4, 3 };
mergesort(a, 0, 5);
for (int i = 0; i < 5; i++) {
cout << a[i] << " ";
}
cout << "\n";
return 0;
}

Queries on permutation 1...N

So we are given a permutation of the numers {1... N}.
We are given an integer k and then k queries of this type:
q(x,y,l,r) - count numbers between position X and Y in the permutation, which are >=l and <=r.
For example:
N - 7: (1 6 3 5 7 4 2)
q(1,4,2,7) -> 3 numbers ( 6, 3 and 5 , since 2<=6<=7 , 2<=3<=7 and 2<=5<=7)
So my attempt was to store the permutation and and position array (too have fast acces to the position of each number)
Then i check which interval is smaller [x,y] or [l,r] and iterate through the smaller.
The answers i get are correct, but i get 0 points, since my solution it's too slow.
Any tips how to make this queries as fast as possible for big N?
#include <iostream>
using namespace std;
int main()
{
int n;
cin >> n;
int q;
cin >> q;
int* perm = new int[n+1];
int* pos = new int[n+1];
for (int i = 1; i <= n; i++)
{
int num;
cin >> num;
perm[i] = num;
pos[num] = i;
}
for (int i = 0; i < q; i++)
{
int x, y, l, r;
cin >> x >>y>> l>> r;
int count = 0;
if (y - x < r - l)
{
for (int i = x; i <= y; i++)
{
if (perm[i] >= l && perm[i] <= r)
count++;
}
cout << count << endl;
}
else
{
int count = 0;
for (int i = l; i <= r; i++)
{
if (pos[i] >= x && pos[i] <= y)
count++;
}
cout << count << endl;
}
}
}

Bit-reversal algorithm by Rutkowska

I found a very interesting paper about bit-reversal algorithm suitable for in-place FFT: "A simple algorithm for the bit-reversal permutation" by
Urszula Rutkowska from 1990 (doi.org/10.1016/0165-1684(91)90008-7).
However, her algorithm G1 does not appear to work as the very first iteration results in out-of-bounds error for that N1 = L << 1 and swap(a + 1, a + N1);. I assume L means the length of input vector.
Please, does anyone know if there was any errata for the paper or how to fix the algorithm?
The paper's pseudocode:
G1(L)
{int i,j,L1
N1,N2,a,b;
unsigned k;
j=0; L1=L-1;
N1=L<<1;N2=N1+1;
for(i=0;i<L1;i++)
{if(i<j)
{ a=i<<1;
b=j<<1;
swap(a,b);
swap(a+N2,b+N2);
swap(a+1,b+N1);
swap(b+1,a+N1);
}
else
if(i==j)
{ a=i<<1;
swap(a+1,a+N1);
}
k=L>>1;
while(k<=j){ j=j-k;
k=k>>1;
}
j+=k;
}
i<<=1;
swap(i+1,i+N1);
}
Screenshot of the paper:
It was pretty garbled, frankly. I had to read the paper for the idea (run Gold's algorithm (G) for L/4 and then derive the swaps for L) and then sort of massage the code into the right form. Here's my final result.
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
static bool is_power_of_two(int L) { return L > 0 && (L & (L - 1)) == 0; }
static void swap(int i, int j) { printf("swap %d,%d\n", i, j); }
static void G(int L) {
assert(is_power_of_two(L));
int j = 0;
for (int i = 0; i < L - 1; i++) {
if (i < j) {
swap(i, j);
}
int k = L >> 1;
while (j >= k) {
j -= k;
k >>= 1;
}
j += k;
}
}
static void G1(int L) {
assert(is_power_of_two(L));
if (L < 4) {
return;
}
int j = 0;
int N1 = L >> 1;
int N2 = N1 + 1;
int L2 = L >> 2;
for (int i = 0; i < L2 - 1; i++) {
if (i < j) {
int a = i << 1;
int b = j << 1;
swap(a, b);
swap(a + N2, b + N2);
swap(a + 1, b + N1);
swap(b + 1, a + N1);
} else if (i == j) {
int a = i << 1;
swap(a + 1, a + N1);
}
int k = L2 >> 1;
while (j >= k) {
j -= k;
k >>= 1;
}
j += k;
}
int a = (L2 - 1) << 1;
swap(a + 1, a + N1);
}
int main(int argc, char *argv[]) {
assert(1 < argc);
int L = atoi(argv[1]);
G(L);
putchar('\n');
G1(L);
}

Resources