Minor changes in indexing take twice memory and time - c

I submitted two slightly different solutions for a problem in which you have remove duplicate elements of an array, so that the relative order does not change.
In first method, I take input sequentially, and store in an array sequentially, and then two nested loops, to check for each element in input array, if it is unique, I store it in another array.
While in second method, I take input sequentially, but store then in reverse order. Rest is same, except the required indexing/iterator changes.
The second one takes twice as much time and memory as first.
Though, the difference is very minor, then why is there a huge difference in time?
Or How can I check exactly why is there this difference?
Actual Problem: You are given an array a consisting of n integers. Your task is to make these array unique by removing duplicates from them.
You have to leave only the rightmost occurrence for each element of the array and remove all other occurrences. The relative order of the remaining unique elements should not be changed.
First method (15 ms, 4 KB):
#include <stdio.h>
int main(void)
{
int n, i, c;
scanf("%i", &n);
int arr[n], nondupe[n];
for (i = 0; i < n; i++)
scanf("%i", arr + i); // Store sequentially
int k = n - 1;
nondupe[k--] = arr[n - 1]; // add last element in non-duplicate array (because rightmost entries are required)
for (i = n - 1; i > 0; i--)
for (c = n - 1; c > k; c--) // Nested loops to iterate over all elements in both arrays
{
if (arr[i - 1] == nondupe[c])
break;
if (c == k + 1)
nondupe[k--] = arr[i - 1];
}
printf("%i\n", n - k - 1);
for (i = k + 1; i < n; i++)
printf("%i ", nondupe[i]);
}
Second (30 ms, 8 KB):
#include <stdio.h>
int main(void)
{
int n, i, c;
scanf("%i", &n);
int arr[n], nondupe[n];
for (i = n; i > 0; i--)
scanf("%i", arr + i - 1);
int k = 0;
nondupe[k++] = arr[0];
for (i = 0; i < n; i++)
for (c = 0; c < k; c++)
{
if (arr[i] == nondupe[c])
break;
if (c == k - 1)
nondupe[k++] = arr[i];
}
printf("%i\n", k);
for (i = k; i > 0; i--)
printf("%i ", nondupe[i - 1]);
}

Related

How to make competitive coding solutions more efficient (BIT wise operations)?

How do I make my code more efficient (in time) pertaining to a competitive coding question (source: codechef starters 73 div 4):
(Problem) Chef has an array A of length N. Chef wants to append a non-negative integer X to the array A such that the bitwise OR of the entire array becomes = Y .
Determine the minimum possible value of X. If no possible value of X exists, output -1.
Input Format
The first line contains a single integer T — the number of test cases. Then the test cases follow.
The first line of each test case contains two integers N and Y — the size of the array A and final bitwise OR of the array A.
The second line of each test case contains N space-separated integers A_1, A_2, ..., A_N denoting the array A.
Please don't judge me for my choice of language .
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int* binary_number(int n) // returns pointer to a array of length 20(based on given constrains) representing binary
{
int* ptc;
ptc = (int*) malloc(20*sizeof(int));
for(int i = 0; i < 20; i++)
{
if((n / (int) pow(2,19-i)) > 0){*(ptc + i) = 1;}
else {*(ptc + i) = 0;}
n = n % (int) pow(2,19-i) ;
}
return ptc;
}
int or_value(int* ptc, int n) // Takes in pointers containing 1 or zero and gives the logical OR
{
for(int k = 0; k < n; n++)
{
if(*ptc == *(ptc + 20*k)){continue;} // pointers are 20 units apart
else{return 1;break;}
}
return *ptc;
}
int main(void) {
int t; scanf("%d", &t);
for (int i = 0; i < t; i++)
{
int n, y;
scanf("%d %d", &n, &y);
int a[n];
for(int j = 0; j < n ; j++)
{
scanf("%d", &a[j]);
}
int b[20*n];
for (int j = 0; j < n; j++)
{
for (int k = 0; k < 20; k++)
{
b[20*j + k] = *(binary_number(a[n])+k);
}
}
int c = 0;
int p = 0;
for (int j = 0; j < 20; j++)
{
if ((*(binary_number(y) + j) == 1) && (or_value((&b[0] + j),n) == 0)){c = c + pow(2,19 - j);}
else if ((*(binary_number(y) + j) == 0) && (or_value((&b[0] + j),n) == 1)){p = 1; break;}
}
if (p==1){printf("-1");}
else {printf("%d\n", c);}
}
return 0;
}

How to use dynamic arrays?

Q: Find all prime numbers between two given Numbers a and b, by using Sieve of Eratosthene.
Im using dynamic array to store prime numbers, but it does nt work.
After debug it, everything is ok untill the last
printf() that crashes.
Code
int main() {
int i, j, n, a, b, k;
int *tab;
scanf("%i", &n); // n is number of sets
for (i = 1; i <= n; i++){
scanf("%i %i", &a, &b);
tab = (int*) malloc(b * sizeof(int)); //allocating the memorry
for (j= 0; j < b; j++){ //seting all numbers to be prime
*(tab + j) = 1;
}
for (j = 2; j <= b; j++){
if (*(tab + j) == 1){
for(k = j; k <= b; k+=j)
*(tab + k) = 0; //seting 0 for all non prime numbers
}
}
for (j = a; j <= b; j++){
if (*(tab + j) == 1){
printf("%i", j); //printing prime numbers
}
}
free(tab);
}
return 0;
}
your second loop should be
for (j = 2; j <= b; j++){
if (*(tab + j) == 1){
for(k = j; k <= b; k += j)
*(tab + k) = 0; //seting 0 for all non prime numbers
}
}
the problem was that because you used multiplication, you tried to access an item in the tab array with index above its allocated size.
edit: and as #melpomene stated, the array is too short. therefore the allocation should be
tab = (int*) malloc((1+b) * sizeof(int));
The problem is, you're accessing array out of its bounds:
*(tab + k*j) = 0;
when
k <= b
j <= b
When you declare array of b elements, you can only access array from 0 to b-1 index.
BTW, as mentioned in comments, using tab[k*j] is more readable and shows clearly that tab is array.
I don't really understand what you mean by sets number, but pseudocode of Sieve of Eratosthenes taken from wiki is applied from 2 to n. So in your case 2 becomes a and n becomes b. You don't need checking all numbers from a to b, root of b will suffice.
Your algorithm should look like:
create array for holding b - a elements
make every element equals 1
make 0 elements which fulfill Eratosthenes rules for complex number
print indexes which contains 1.

Is it the efficeint program to rotate array in left direction?

#include<stdio.h>
#include<stdlib.h>
main()
{
int i,j,l,m,n;
j=0;
printf("\nenter 5 element single dimension array\n");
printf("enter shift rate\n");
scanf("%d",&n);
/* Here we take input from user that by what times user wants to rotate the array in left. */
int arr[5],arrb[n];
for(i=0;i<=4;i++){
scanf("%d",&arr[i]);
}
/* Here we have taken another array. */
for(i=0;i<=4;i++){
printf("%d",arr[i]);
}
for(i=0;i<n;i++){
arrb[j]=arr[i];
j++;
// These loop will shift array element to left by position which's entered by user.
}
printf("\n");
for(i=0;i<=3;i++){
arr[i]=arr[i+n];
}
for(i=0;i<=4;i++){
if(n==1 && i==4)
break;
if(n==2 && i==3)
break;
if(n==3 && i==2)
break;
printf("%d",arr[i]);
}
//To combine these two arrays. Make it look like single array instead of two
for(i=0;i<n;i++){
printf("%d",arrb[i]);
}
// Final sorted array will get printed here
}
Is it the efficeint program to rotate array in left direction?
Actually, very complicated, and some problems contained:
for(i = 0; i < n; i++)
{
arrb[j] = arr[i];
j++;
}
Why not simply:
for(i = 0; i < n; i++)
{
arrb[i] = arr[i];
}
There is no need for a second variable. Still, if n is greater than five, you get into trouble, as you will access arr out of its bounts (undefined behaviour!). At least, you should check the user input!
for(i = 0; i <=3 ; i++)
{
arr[i] = arr[i + n];
}
Same problem: last accessible index is 4 (four), so n must not exceed 1, or you again access the array out of bounds...
Those many 'if's within the printing loop for the first array cannot be efficient...
You can have it much, much simpler:
int arr[5], arrb[5];
// ^
for(int i = 0; i < 5; ++i)
arrb[i] = arr[(i + n) % 5];
This does not cover negative values of n, though.
arrb[i] = arr[(((i + n) % 5) + 5) % 5];
would be safe even for negative values... All you need now for the output is:
for(int i = 0; i < 5; ++i)
printf("%d ", arrb[i]);
There would be one last point uncovered, though: if user enters for n a value greater than INT_MAX - 4, you get a signed integer overflow, which again is undefined behaviour!
We can again cover this by changing the index formula:
arrb[i] = arr[(5 + i + (n % 5)) % 5];
n % 5 is invariant, so we can move it out of the loop:
n %= 5;
for(int i = 0; i < 5; ++i)
arrb[i] = arr[(5 + i + n) % 5];
Finally, if we make n positive already outside, we can spare the addition in the for loop.
n = ((n % 5) + 5) % 5;
for(int i = 0; i < 5; ++i)
arrb[i] = arr[(i + n) % 5]; // my original formula again...
Last step is especially worth considering for very long running loops.
I think you want to do something like this (you should check that 0 <= n <= 5, too):
int b[5];
int k = 0;
for(i=0; i<5; i++){
if (i < 5 - n)
b[i] = arr[i+n];
else
{
b[i] = arr[k];
k++;
}
}
Array b is used to save the rotated matrix.

Negative numbers are printed

This is a program on sorting integers.
#include <stdio.h>
int main(void) {
int n, i, j, k;
int nmbr[100];
printf("\n How many numbers ? ");
scanf("%d", &n);
printf("\n");
for (i = 0; i < n; ++i) {
printf(" Number %d : ", i + 1);
scanf("%d", &nmbr[i]);
}
for (i = 0; i < n; ++i) {
for (j = 0; j < n; ++j) {
if (nmbr[j] > nmbr[j + 1]) {
k = nmbr[j];
nmbr[j] = nmbr[j + 1];
nmbr[j + 1] = k;
}
}
}
printf("\n Numbers after sorting : \n");
for (i = 0; i < n; ++i) {
printf (" %d", nmbr[i]);
}
return 0;
}
It works fine, but when I enter some number that contains more than 2 digits, the first number that is printed is negative and really big. I don't also get the last integer too. I enter N as 4, then the numbers I entered were 25, 762, 588, and 34. The result I get is:
-1217260830 25 34 588
What seems to be the problem?
You are running the loop as for (j = 0; j < n; ++j) which means j will have values from 0 to n-1 which are valid array indices (or array elements with relevant values).
But, inside that loop you are accessing an element beyond the last. For instance, in
if (nmbr[j] > nmbr[j + 1])
you are accessing nmbr[j + 1]. If the current value of j in n-1, then you are accessing nmbr[n-1 + 1] i.e. nmbr[n] which will be a value outside the array and may contain a garbage value (which might as well be negative!).
If you are trying something like Bubblesort, you might want to run the inner loop like for (j = 0; j < n - 1; ++j).
There are multiple problems in your code:
You do not check the return values of scanf(). If any of these input operations fail, the destination values remain uninitialized, invoking undefined behavior and potentially producing garbage output.
You do not verify that the number of values provided by the user is at most 100. The reading loop will cause a buffer overflow if n is too large.
Your sorting logic is flawed: in the nested loop, you refer to nmbr[j + 1] which is beyond the values read from the user. This invokes undefined behavior: potentially causing a garbage value to appear in the output.
Here is a corrected version:
#include <stdio.h>
int main(void) {
int n, i, j, k;
int nmbr[100];
printf("\n How many numbers ? ");
if (scanf("%d", &n) != 1 || n > 100) {
printf("input error\n");
return 1;
}
printf("\n");
for (i = 0; i < n; ++i) {
printf(" Number %d : ", i + 1);
if (scanf("%d", &nmbr[i]) != 1) {{
printf("input error\n");
return 1;
}
}
for (i = 0; i < n; ++i) {
for (j = 0; j < n - 1; ++j) {
if (nmbr[j] > nmbr[j + 1]) {
k = nmbr[j];
nmbr[j] = nmbr[j + 1];
nmbr[j + 1] = k;
}
}
}
printf("\n Numbers after sorting :\n");
for (i = 0; i < n; ++i) {
printf (" %d", nmbr[i]);
}
printf("\n");
return 0;
}
Your Sorting Logic is wrong. It should be:
for (i = 0; i < n; ++i){
for (j = 0; j < (n-1); ++j){
if (nmbr[j] > nmbr[j + 1]){
k = nmbr[j];
nmbr[j] = nmbr[j + 1];
nmbr[j + 1] = k;
}
}
You are trying to access out of bounds of array, when you iterate in your second loop using j. This is causing the garbage value.
As per your example involving 4 elements, when you try to access j+1, it will try to access nmbr[3+1] in the last iteration of second loop which leads to out of bounds access.
Problem is with the sorting logic as suggested by fellow coders. But It is always good coding habit to initialize the variables. Also use the qualifier if are dealing with positive numbers only.
unsigned int n = 0 , i = 0, j = 0, k = 0;
unsigned int nmbr[100] = {0};
If you would have initialized them, out put of your program would be following, which might help you tracing the problem by yourself.
0 25 34 588

Calculating large power of a number in c

I am writing a program in c to store 2^100000, and I am using arrays to store the result.
Here is the full code:
#include <stdio.h>
#include <math.h>
int main()
{
int test, n, i, j, x, resul;
int a[200], m, temp;
scanf("%d", &test);
for (i = 0; i < test; i++) {
a[0] = 3; // initializes array with only 1 digit, the digit 1.
m = 1; // initializes digit counter
scanf("%d", &n);
temp = 0; // Initializes carry variable to 0.
for (i = 1; i < n; i++) {
for (j = 0; j < m; j++) {
x = a[j] * 2 + temp; //x contains the digit by digit product
a[j] = x % 10; //Contains the digit to store in position j
temp = x / 10; //Contains the carry value that will be stored on later indexes
}
while (temp > 0) { //while loop that will store the carry value on array.
a[m] = temp % 10;
temp = temp / 10;
m++; // increments digit counter
}
}
for (i = m - 1; i >= 0; i--) //printing answer
printf("%d", a[i]);
}
return 0;
}
Can some one tell me a more efficient way to do so to reduce the time complexity?
2^n in binary is an (n+1)-digit integer with every bit set to 0 except the most significant bit being set to 1. e.g: 32 = 2^5 = 0b100000
Likewise, 2^100000 can be computed by setting the 100001-th bit in a zeroed 100001 bit long integer to 1. O(1) is as time efficient as you can go.
There are several problems with your code:
The array a is defined with a size of only 200 digits. This is much too small for 2^100000 that has 30103 digits. You should increase the array size and check for overflow in the multiplication algorithm.
You initialize a[0] = 3; and comment this as the digit 1. Indeed you should write a[0] = 1;.
The second loop for (i = 1; i < n; i++) should include the desired power number: you should write for (i = 1; i <= n; i++).
You use the same loop variable for the outer loop and the second level ones, causing incorrect behavior.
You do not test the return value of scanf, causing undefined behavior on invalid input.
You do not check for overflow, invoking undefined behavior on large values.
Here is a corrected version:
#include <stdio.h>
int main()
{
int n, i, j, x, m, test, temp;
int a[32000];
if (scanf("%d", &test) != 1)
return 1;
while (test-- > 0) {
if (scanf("%d", &n) != 1)
break;
a[0] = 1; // initializes array with only 1 digit, the number 1.
m = 1; // initializes digit counter
temp = 0; // Initializes carry variable to 0.
for (i = 1; i <= n; i++) {
for (j = 0; j < m; j++) {
x = a[j] * 2 + temp; //x contains the digit by digit product
a[j] = x % 10; //Contains the digit to store in position j
temp = x / 10; //Contains the carry value that will be stored on later indexes
}
// while loop that will store the carry value on array.
if (temp > 0) {
if (m >= (int)(sizeof(a)/sizeof(*a)))
break;
a[m++] = temp;
temp = 0;
}
}
if (temp > 0) {
printf("overflow");
} else {
for (i = m - 1; i >= 0; i--) //printing answer
putchar('0' + a[i]);
}
printf("\n");
}
return 0;
}
Running this code with input 1 and 100000 on my laptop takes about 6,5 seconds. That's indeed quite inefficient. Using a few optimization techniques that do not really change the complexity of this simple iterative algorithm still can yield a dramatic performance boost, possibly 100 times faster.
Here are some ideas:
store 9 digits per int in the array instead of just 1.
multiply by 2^29 in each iteration instead of just 2, using long long to compute the intermediary result. Initialize the first step to 1 << (n % 29) to account for n not being a multiple of 29. 2^29 is the largest power of 2 less than 10^9.
Here is version that implements these two ideas:
#include <stdio.h>
int main() {
int n, i, j, m, test, temp;
int a[32000];
if (scanf("%d", &test) != 1)
return 1;
while (test-- > 0) {
if (scanf("%d", &n) != 1)
break;
i = n % 29;
n /= 29;
a[0] = 1 << i;
m = 1;
temp = 0;
for (i = 1; i <= n; i++) {
for (j = 0; j < m; j++) {
long long x = a[j] * (1LL << 29) + temp;
a[j] = x % 1000000000;
temp = x / 1000000000;
}
if (temp > 0) {
if (m >= (int)(sizeof(a)/sizeof(*a)))
break;
a[m++] = temp;
temp = 0;
}
}
if (temp > 0) {
printf("overflow");
} else {
printf("%d", a[m - 1]);
for (i = m - 2; i >= 0; i--)
printf("%09d", a[i]);
}
printf("\n");
}
return 0;
}
Running it on the same laptop computes the correct result in only 33ms, that's 200 times faster.
The Time Complexity is the same, but implementation is much more efficient.
Be aware that native C integers are limited, in practice to some power of two related to the word size of your computer (e.g. typically 32 or 64 bits). Read about <stdint.h> and int32_t & int64_t.
Maybe you want some bignums (or bigints), a.k.a. arbitrary precision arithmetic.
The underlying algorithms are very clever (and more efficient than the naive ones you learned in school). So don't try to reinvent them, and use a library like GMPlib

Resources