I am trying to solve this problem:
In an integer array all numbers occur exactly twice, except for a single number which occurs exactly once.
A simple solution is to sort the array and then test for non repetition. But I am looking for better solution that has time complexity of O(n).
You can use "xor" operation on the entire array. Each pair of numbers will cancel each other, leaving you with the sought value.
int get_orphan(int const * a, int len)
{
int value = 0;
for (int i = 0; i < len; ++i)
value ^= a[i];
// `value` now contains the number that occurred odd number of times.
// Retrieve its index in the array.
for (int i = 0; i < len; ++i)
{
if (a[i] == value)
return i;
}
return -1;
}
Related
I have an array, say 1,3,3,1,2 The output of the code must be 4(2 repetitions of 1 + 2 repetitions of 3=4). How can I do this in C? Here's my attempt.
#include <stdio.h>
int main(){
int n,i,j,temp;
scanf("%d",&n);
int arr[n];
for(i=0;i<n;i++){
scanf("%d",&arr[i]);
}
for(i=0;i<n;i++){
int min = i;
for(j=i+1;j<n;j++){
if(arr[j]<arr[min]) min=j;
}
temp= arr[min];
arr[min]=arr[i];
arr[i]=temp;
}
int count=1;
for(i=0;i<n;i++){
if(arr[i]==arr[i+1])count++;
else continue;
}
printf("%d",count);
}
What you need is to change this for loop.
int count=1;
for(i=0;i<n;i++){
if(arr[i]==arr[i+1])count++;
else continue;
}
It can look for example the following way
int count = 0;
for ( i = 0; i < n; )
{
int j = i;
while ( ++i < n && arr[i-1] == arr[i] );
if ( !( i - j < 2 ) ) count += i - j;
}
It looks like your loop has a couple of problems.
It indexes past the end of the array, which is undefined behavior
It doesn't understand when to count the first item in a group of duplicates
Regarding #1 it's nice to just start your loop at 1 instead of 0 and then check index i-1 against i.
Regarding #2 your code works but only when there's only one number that has duplicates. This is because you started the count at 1. However, when you encounter another group, that assumption breaks down. The simplest way is to just record whether you're starting a new group.
Let's put this all together:
int count = 0;
int first = 1;
for(i = 1; i < n; i++) {
if (arr[i-1] == arr[i]) {
count += first + 1;
first = 0;
} else {
first = 1;
}
}
As for the sorting step, it's using a wildly inefficient algorithm. This is fine for small datasets, but you'll have a problem if you have a very large number of inputs. It would be wise to use something like qsort instead. There are many examples out there for how to do this.
So, your runtime right now is O(N^2). With quicksort it becomes O(N.logN).
You can probably reduce runtime further with something like a hash table that simply stores how many of each value you've found, which you update as they arrive.
If your data ranges are well-defined and small enough, you might also benefit from using a large array instead of a hash table and store a single bit for each possible number representing when a number is seen. Actually for your case you'd need two of these because of the "first in the group" problem. Now, each number that arrives sets the "seen" bit. If it was already seen, set the "duplicate" bit and increment the count. If the "duplicate" bit is not set, increment the count. Now you pretty much guarantee blazing-fast O(N) runtime where testing for and counting a duplicate value is O(1).
EDIT:
I forgot to mention that I do not want to allocate another temporarily array.
I am trying to solve a problem in C, which is:
Suppose you were given an array a and it's size N. You know that all of the elements in the array are between 0 to n-1. The function is supposed to return 0 if there is a missing number in the range (0 to n-1). Otherwise, it returns 1. As you can understand, duplicates are possible. The thing is that its supposed to run on O(n) runtime.
I think I managed to do it but i'm not sure. From looking at older posts here, it seems almost impossible and the algorithm seems much more complicated then the algorithm I have. Therefore, something feels wrong to me.
I could not find an input that returns the wrong output yet thou.
In any case, I'd appreciate your feedback- or if you can think of an input that this might not work for. Here's the code:
int missingVal(int* a, int size)
{
int i, zero = 0;
for (i = 0; i < size; i++)
//We multiply the element of corresponding index by -1
a[abs(a[i])] *= -1;
for (i = 0; i < size; i++)
{
//If the element inside the corresponding index is positive it means it never got multiplied by -1
//hence doesn't exist in the array
if (a[i] > 0)
return 0;
//to handle the cases for zeros, we will count them
if (a[i] == 0)
zero++;
}
if (zero != 1)
return 0;
return 1;
}
Just copy the values to another array placing each value in its ordinal position. Then walk the copy to see if anything is missing.
your program works and it is in O(N), but it is quite complicated and worst it modify the initial array
can be just that :
int check(int* a, int size)
{
int * b = calloc(size, sizeof(int));
int i;
for (i = 0; i != size; ++i) {
b[a[i]] = 1;
}
for (i = 0; i != size; ++i) {
if (b[i] == 0) {
free(b);
return 0;
}
}
free(b);
return 1;
}
This problem is the same as finding out if your array has duplicates. Here's why
All the numbers in the array are between 0 and n-1
The array has a size of n
If there's a missing number in that range, that can only mean that another number took its place. Which means that the array must have a duplicate number
An algorithm in O(n) time & O(1) space
Iterate through your array
If the sign of the current number is positive, then make it negative
If you found a negative this means that you have a duplicate. Since all items are originally greater (or equal) than 0
Implementation
int missingVal(int arr[], int size)
{
// Increment all the numbers to avoid an array with only 0s
for (int i = 0; i < size; i++) arr[i]++;
for (int i = 0; i < size; i++)
{
if (arr[abs(arr[i])] >= 0)
arr[abs(arr[i])] = -arr[abs(arr[i])];
else
return 0;
}
return 1;
}
Edit
As Bruno mentioned if we have an array with all zeros, we could have run into a problem. This is why I included in this edit an incrementation of all the numbers.
While this add another "pass" into the algorithm, the solution is still in O(n) time & O(1) space
Edit #2
Another great suggestion from Bruno which optimizes this, is to look if there's more than one zero instead of incrementing the array.
If there's 2 or more, we can directly return 0 since we have found a duplicate (and by the same token that not all the numbers in the range are in the array)
To overcome the requirement that excludes any extra memory consumption, the posted algorithm changes the values inside the array by simply negating their value, but that would leave index 0 unchanged.
I propose a different mapping: from [0, size) to (-1 - size, -1], so that e.g. {0, 1, 2, 3, 4, ...} becomes {-1, -2, -3, -4, -5, ...}. Note that, for a two's complement representation of integers, INT_MIN = -INT_MAX - 1.
// The following assumes that every value inside the array is in [0, size-1)
int missingVal(int* a, int size) // OT: I find the name misleading
{
int i = 0;
for (; i < size; i++)
{
int *pos = a[i] < 0
? a + (-a[i] - 1) // A value can already have been changed...
: a + a[i];
if ( *pos < 0 ) // but if the pointed one is negative, there's a duplicate
break;
*pos = -1 - *pos;
}
return i == size; // Returns 1 if there are no duplicates
}
If needed, the original values could be restored, before returning, with a simple loop
if ( i != size ) {
for (int j = 0; j < size; ++j) {
if ( a[j] < 0 )
a[j] = -a[j] - 1;
}
} else { // I already know that ALL the values are changed
for (int j = 0; j < size; ++j)
a[j] = -a[j] - 1;
}
I have got an assignment and i'll be glad if you can help me with one question
in this assignment, i have a question that goes like this:
write a function that receives an array and it's length.
the purpose of the function is to check if the array has all numbers from 0 to length-1, if it does the function will return 1 or 0 otherwise.The function can go through the array only one.
you cant sort the array or use a counting array in the function
i wrote the function that calculate the sum and the product of the array's values and indexes
int All_Num_Check(int *arr, int n)
{
int i, index_sum = 0, arr_sum = 0, index_multi = 1, arr_multi = 1;
for (i = 0; i < n; i++)
{
if (i != 0)
index_multi *= i;
if (arr[i] != 0)
arr_multi *= arr[i];
index_sum += i;
arr_sum += arr[i];
}
if ((index_sum == arr_sum) && (index_multi == arr_multi))
return 1;
return 0;
}
i.e: length = 5, arr={0,3,4,2,1} - that's a proper array
length = 5 , arr={0,3,3,4,2} - that's not proper array
unfortunately, this function doesnt work properly in all different cases of number variations.
i.e: length = 5 , {1,2,2,2,3}
thank you your help.
Checking the sum and product is not enough, as your counter-example demonstrates.
A simple solution would be to just sort the array and then check that at every position i, a[i] == i.
Edit: The original question was edited such that sorting is also prohibited. Assuming all the numbers are positive, the following solution "marks" numbers in the required range by negating the corresponding index.
If any array cell already contains a marked number, it means we have a duplicate.
int All_Num_Check(int *arr, int n) {
int i, j;
for (i = 0; i < n; i++) {
j = abs(arr[i]);
if ((j >= n) || (arr[j] < 0)) return 0;
arr[j] = -arr[j];
}
return 1;
}
I thought for a while, and then i realized that it is a highly contrained problem.
Things that are not allowed:
Use of counting array.
Use of sorting.
Use of more than one pass to the original array.
Hence, i came up with this approach of using XOR operation to determine the results.
a ^ a = 0
a^b^c = a^c^b.
Try this:
int main(int argc, char const *argv[])
{
int arr[5], i, n , temp = 0;
for(i=0;i<n; i++){
if( i == 0){
temp = arr[i]^i;
}
else{
temp = temp^(i^arr[i]);
}
}
if(temp == 0){
return 1;
}
else{
return 0;
}
}
To satisfy the condition mentioned in the problem, every number has to occour excatly once.
Now, as the number lies in the range [0,.. n-1], the looping variable will also have the same possible range.
Variable temp , is originally set to 0.
Now, if all the numbers appear in this way, then each number will appear excatly twice.
And XORing the same number twice results in 0.
So, if in the end, when the whole array is traversed and a zero is obtained, this means that the array contains all the numbers excatly once.
Otherwise, multiple copies of a number is present, hence, this won't evaluate to 0.
I have a function that takes a one-dimensional array of N positive integers and returns the number of elements that are larger than all the next. The problem is exist a function to do it that in a better time? My code is the following:
int count(int *p, int n) {
int i, j;
int countNo = 0;
int flag = 0;
for(i = 0; i < n; i++) {
flag = 1;
for(j = i + 1; j < n; j++) {
if(p[i] <= p[j]) {
flag = 0;
break;
}
}
if(flag) {
countNo++;
}
}
return countNo;
}
My solution is O(n^2). Can it be done better?
You can solve this problem in linear time(O(n) time). Note that the last number in the array will always be a valid number that fits the problem definition. So the function will always output a value that will be greater than equal to 1.
For any other number in the array to be a valid number it must be greater than or equal to the greatest number that is after that number in the array.
So iterate over the array from right to left keeping track of the greatest number found till now and increment the counter if current number is greater than or equal to the greatest found till now.
Working code
int count2(int *p, int n) {
int max = -1000; //this variable represents negative infinity.
int cnt = 0;
int i;
for(i = n-1; i >=0; i--) {
if(p[i] >= max){
cnt++;
}
if(p[i] > max){
max = p[i];
}
}
return cnt;
}
Time complexity : O(n)
Space complexity : O(1)
It can be done in O(n).
int count(int *p, int n) {
int i, currentMax;
int countNo = 0;
currentMax = p[n-1];
for(i = n-1; i >= 0; i--) {
if(currentMax < p[i])
{
countNo ++;
currentMax = p[i];
}
}
return countNo;
}
Create an auxillary array aux:
aux[i] = max{arr[i+1], ... ,arr[n-1] }
It can be done in linear time by scanning the array from right to left.
Now, you only need the number of elements such that arr[i] > aux[i]
This is done in O(n).
Walk backwards trough the array, and keep track of the current maximum. Whenever you find a new maximum, that element is larger than the elements following.
Yes, it can be done in O(N) time. I'll give you an approach on how to go about it. If I understand your question correctly, you want the number of elements that are larger than all the elements that come next in the array provided the order is maintained.
So:
Let len = length of array x
{...,x[i],x[i+1]...x[len-1]}
We want the count of all elements x[i] such that x[i]> x[i+1]
and so on till x[len-1]
Start traversing the array from the end i.e. at i = len -1 and keep track of the largest element that you've encountered.
It could be something like this:
max = x[len-1] //A sentinel max
//Start a loop from i = len-1 to i = 0;
if(x[i] > max)
max = x[i] //Update max as you encounter elements
//Now consider a situation when we are in the middle of the array at some i = j
{...,x[j],....x[len-1]}
//Right now we have a value of max which is the largest of elements from i=j+1 to len-1
So when you encounter an x[j] that is larger than max, you've essentially found an element that's larger than all the elements next. You could just have a counter and increment it when that happens.
Pseudocode to show the flow of algorithm:
counter = 0
i = length of array x - 1
max = x[i]
i = i-1
while(i>=0){
if(x[i] > max){
max = x[i] //update max
counter++ //update counter
}
i--
}
So ultimately counter will have the number of elements you require.
Hope I was able to explain you how to go about this. Coding this should be a fun exercise as a starting point.
I'm trying to find the sum of all positive numbers in an array. So far, I have come up with this;
int largest_sum_sequence(int list, int size)
{
int sum = 0, *index = 0;
for (index < size; index = size; index++)
{
if (list[index] > 0)
{
sum = sum + list[index];
}
}
printf("%d", sum);
return sum;
}
My program keeps crashing. I'm pretty sure it has something to do with index. Whenever I use list[index] it says that I need to use a pointer for index, but I don't know how to do that properly. Help is appreciated!
You do not want index to be a pointer, and your for loop is incorrect. Try:
int sum = 0, index = 0;
for (; index < size; index++)
The compiler tells you actually exactly what to do.
First of all you need an array or a pointer as a parameter, like
int largest_sum_sequence(int *list, int size)
{
....
}
or
int largest_sum_sequence(int list[], int size)
{
....
}
where the latter might be easier to read.
The second thing is, you don't want to iterate with a pointer through the list, but more with a simple integer.
so you declare
int sum = 0, index = 0;
The for() loop isn't quite correct either. Instead of initializing something, you test if index < size and discard the result. This is syntactically correct, but doesn't make sense.
The first part in the for-statement is executed before the loop starts, but doesn't influence the starting itself. It is meant for initializing the loop variable (index in this case). The second part is the termination condition. The loop terminates if the condition evaluates to false. The last part of the loop is for incrementing (or decrementing, more abstract, changing) the loop variable.
Having said this, it is halfway obvious it should look like:
for (index = 0; index < size; ++index) {
....
}
Assuming your list isn't very long (such that the sum could exceed 2^{31} - 1), the rest is correct. Although I'd add an \n to the printf() pattern.
Where is the list coming from? Can't answer that from your code, but you've room for mistakes here too :-)
Function argument doesn't except an array.
Quick function I wrote.
int getSums(int myArray[], int size)
{
int total = 0;
int index = size;
for ( int i = 0; i < index; i++)
{
if (myArray[i] > 0)
total += myArray[i];
}
return ( total );
};