Modify any element of the array - c

Given an array of integers , you can modify any of a number of arbitrary positive integer , and ultimately makes the entire array is strictly increasing and are positive integers , and asked at least need to change a few numbers
input: 5 1 2 2 3 4
output: 3
and there is what i have tried ,Each number in order to reduce more a ( first number minus one , then the second number minus two ,the third number minus three)
#include <stdio.h>
int Modify_the_array(int B[],int n);
int max(int a,int b);
int main(int argc,char *argv) {
int before_array[]={1,2,3,4,1,2,3,4,5};
int len=sizeof(before_array[0])/sizeof(before_array);
int b;
b=Modify_the_array(before_array,len);
printf("%d\n",b);
return 0;
}
int max(int a,int b){
return a>b?a:b;
}
int Modify_the_array(int B[],int len) {
int i,b=0,n=1;
int maxsofar,tmp,j;
for (i=0;i<len;i++){
B[i]=B[i]-n;
n++;
}
maxsofar=0;
tmp=0;
for(i=0;i<len;i++) {
for (j=i+1;j<len;j++) {
if (B[j]==B[i]&&B[i]>1) {
maxsofar=max(maxsofar,++tmp);
b=len-maxsofar;
}
}
}
return b;
}
somebody recommend there is another solution for this question,more efficently ,can anyone give me some advice,thank in advance

I came across the same problem recently. To make clear:
Problem Statement
You are given a sequence of integers a1,a2,a3.....an. You are free to replace any integer with any other positive integer. How many integers must be replaced to make the resulting sequence strictly increasing?
Input Format
The first line of the test case contains an integer N - the number of entries in the sequence.
The next line contains N space separated integers where the ith integer is ai.
Output Format
Output the minimal number of integers that should be replaced to make the sequence strictly increasing.
Given your input, len = 5, arr = [1 2 2 3 4], after minus index+1, get [0 0 -1 -1 -1].
Ignoring negative elements(these must be changed), compute Longest Increasing Subsequence(nondecreasing for this problem), which is a classic Dynamic Programming problem.
Denote the length of LIS = n(these elements will not be changed). So the final answer(the part doesn't belong to the increasing subsequence and the ignored negative part) is len-n(5-2=3).
We can compute LIS in O(nlogn) time with O(n) space.
int solve(vector<int> &arr) {
int len = arr.size();
for(int i = 0; i < len; i++) {
arr[i] -= i+1;
}
vector<int> lis(len,0);
int n = 0;
for(int i = 0; i < len; i++) {
if(arr[i] >= 0) {
int pos = binarysearchPos(lis,n,arr[i]);
lis[pos] = arr[i];
if(n == pos)
n++;
}
}
return len-n;
}
int binarysearchPos(vector<int> &arr, int n, int target) {
if(n == 0)
return 0;
if(arr[n-1] <= target)
return n;
int low = 0, high = n-1;
while(low < high) {
int mid = (low+high)/2;
if(arr[mid] > target) {
high = mid;
} else {
low = mid+1;
}
}
return low;
}

Related

finding negative number closest to 0 in array (log n complexity)

I have a question: write a function that gets an ascending array of whole numbers and their size.
It is given that the array contains at least one negative number and one positive number, and I need to find the closest negative number to the number 0.
for example: [-30,-25,-18,-10,11,11,20,30]
the function will return -10.
The problem is that I need to do it in O(log n) complexity and I don't know how to do this.
I made it only with O(n).
`
int f(int* arr, int size)
{
int i;
int result = arr[0];
for (i = 1;i < size;i++)
{
if (arr[i] < 0 && result < arr[i])
result = arr[i];
else
return result;
}
return result;
}
Here is a simple C implementation of a binary search, which works in O(log n) time.
#include <stdio.h>
int find(int *arr, size_t size)
{
size_t bot = 0;
size_t top = size; // it will never be top
size_t dif;
while((dif = top - bot) > 1) {
size_t mid = bot + dif / 2;
if(arr[mid] >= 0) { // eliminate non-negatives
top = mid;
}
else {
bot = mid;
}
}
return arr[bot];
}
int main(void) {
int arr[] = { -30, -25, -18, -10, 11, 11, 20, 30 };
size_t size = sizeof arr / sizeof arr[0]; //parentheses only needed for types
printf("%d\n", find(arr, size));
}
I like to use a binary search so that the top element is never a candidate.
Program output:
-10
Here's a possible way
int f( int *n, int size )
{
int low = 0, mid, high = size-1;
while( (mid = (low+high)/2) && n[mid] * n[mid+1] > 0 ) n[mid] < 0 ? (low = mid) : (high = mid);
return n[mid] ? n[mid] : n[mid-1];
}
I posted it condensed to give you something to do. Rewrite it properly using if else and do while.
The program uses min, max and mid as indexes for the array n[].
min is set to 0 and will always be the index of a negative number, max is set to size-1 and will always be the index of a positive number or of a 0. mid will always be between them (or exactly them).
The loop breaks when find an element (that is n[mid]) such that multiplied for the next one gives a negative number or zero.
Then the function returns n[mid], unless it is 0, in this case it returns the element before n[mid].
Note that if the array can contain dupes, then you need to handle the case of multiple 0s adding something like that at the end
while( !n[mid] ) --mid;
EDIT: I forgot to tell you that since the algorithm for the function is a binary search, it suits your time complexity requirements.

Non divisible subset-Hackerrank solution in C

I am new to programming and C is the only language I know. Read a few answers for the same question written in other programming languages. I have written some code for the same but I only get a few test cases correct (4 to be precise). How do I edit my code to get accepted?
I have tried comparing one element of the array with the rest and then I remove the element (which is being compared with the initial) if their sum is divisible by k and then this continues until there are two elements in the array where their sum is divisible by k. Here is the link to the question:
https://www.hackerrank.com/challenges/non-divisible-subset/problem
#include<stdio.h>
#include<stdlib.h>
void remove_element(int array[],int position,long int *n){
int i;
for(i=position;i<=(*n)-1;i++){
array[i]=array[i+1];
}
*n=*n-1;
}
int main(){
int k;
long int n;
scanf("%ld",&n);
scanf("%d",&k);
int *array=malloc(n*sizeof(int));
int i,j;
for(i=0;i<n;i++)
scanf("%d",&array[i]);
for(i=n-1;i>=0;i--){
int counter=0;
for(j=n-1;j>=0;j--){
if((i!=j)&&(array[i]+array[j])%k==0)
{
remove_element(array,j,&n);
j--;
continue;
}
else if((i!=j)&&(array[i]+array[j])%k!=0){
counter++;
}
}
if(counter==n-1){
printf("%ld",n);
break;
}
}
return 0;
}
I only get about 4 test cases right from 20 test cases.
What Gerhardh in his comment hinted at is that
for(i=position;i<=(*n)-1;i++){
array[i]=array[i+1];
}
reads from array[*n] when i = *n-1, overrunning the array. Change that to
for (i=position; i<*n-1; i++)
array[i]=array[i+1];
Additionally, you have
remove_element(array,j,&n);
j--;
- but j will be decremented when continuing the for loop, so decrementing it here is one time too many, while adjustment of i is necessary, since remove_element() shifted array[i] one position to the left, so change j-- to i--.
Furthermore, the condition
if(counter==n-1){
printf("%ld",n);
break;
}
makes just no sense; remove that block and place printf("%ld\n", n); before the return 0;.
To solve this efficiently, you have to realize several things:
Two positive integer numbers a and b are divisible by k (also positive integer number) if ((a%k) + (b%k))%k = 0. That means, that either ((a%k) + (b%k)) = 0 (1) or ((a%k) + (b%k)) = k (2).
Case (1) ((a%k) + (b%k)) = 0 is possible only if both a and b are multiples of k or a%k=0 and b%k=0. For case (2) , there are at most k/2 possible pairs. So, our task is to pick elements that don't fall in case 1 or 2.
To do this, map each number in your array to its corresponding remainder by modulo k. For this, create a new array remainders in which an index stands for a remainder, and a value stands for numbers having such remainder.
Go over the new array remainders and handle 3 cases.
4.1 If remainders[0] > 0, then we can still pick only one element from the original (if we pick more, then sum of their remainders 0, so they are divisible by k!!!).
4.2 if k is even and remainders[k/2] > 0, then we can also pick only one element (otherwise their sum is k!!!).
4.3 What about the other numbers? Well, for any remainder rem > 0 make sure to pick max(remainders[rem], remainders[k - rem]). You can't pick both since rem + k - rem = k, so numbers from such groups can be divisible by k.
Now, the code:
int nonDivisibleSubset(int k, int s_count, int* s) {
static int remainders[101];
for (int i = 0; i < s_count; i++) {
int rem = s[i] % k;
remainders[rem]++;
}
int maxSize = 0;
bool isKOdd = k & 1;
int halfK = k / 2;
for (int rem = 0; rem <= halfK; rem++) {
if (rem == 0) {
maxSize += remainders[rem] > 0;
continue;
}
if (!isKOdd && (rem == halfK)) {
maxSize++;
continue;
}
int otherRem = k - rem;
if (remainders[rem] > remainders[otherRem]) {
maxSize += remainders[rem];
} else {
maxSize += remainders[otherRem];
}
}
return maxSize;
}

Bubble sort takes a long time then segfaults

Given an integer n, write a C program to count the number of digits that are in the same position after forming an integer m with the digits in n but in ascending order of digits. For example, if the value of n is 351462987 then value of m will be 123456789 and digits 4 and 8 will be in the same position.
This is my code:
#include<stdio.h>
void bubble(int a[],int length)
{
for (int i=0;i<length;i++)
{
for (int j=0;j<length;j++)
{
if (a[j]>a[j+1])
{
int t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
}
int check(int a[],int b[],int length)
{
int count=0;
for (int i=0;i<length;i++)
{
if (a[i]==b[i])
{
count=i;
break;
}
}
return count;
}
int length(int n)
{
int l;
while (n!=0)
{
n=n/10;
l++;
}
return l;
}
void main()
{
int n,arrn[100],temp[100];
scanf("%d",&n);
int l=length(n);
for (int i=0;i<l;i++)
{
arrn[l-i-1]=n%10;
temp[l-i-1]=arrn[l-i-1];
n=n/10;
}
bubble(temp,l);
int c=check(arrn,temp,l);
printf("%d",c);
}
I am able to compile the code but when I execute it it takes a long time only to show segmentation fault.
Easy answer, use a debugger.
Here are some problem with your code:
In length function, l is not initialized and as such can have an arbitrary initial value. In your case, you probably want to start at 0.
int l = 0;
Your check function probably don't do what you want. As written count is not a count but the index of a position where numbers match. As there is a break statement in the block, the loop will exit after the first match so the return value would be the position of the first match or 0 if no match was found.
Your bubble function goes one item too far when i is equal to length - 1 as you access item a[j + 1] in the inner loop which is out of bound. In that case, it is simpler to start at 1 instead of 0 and compare item at index i - 1 with item at index i.
Some extra notes:
It is recommended to add whitespace around operators and after a comma separating multiple declarations to improve readability. Here are some example of lines with improved readability.
int n, arrn[100], temp[100];
int count = 0;
for (int i = 0; i < length; i++)…
if (a[i] == b[i])…
arrn[l - i - 1] =n % 10;
temp[l - i - 1] = arrn[l - i - 1];
int check(int a[], int b[], int length)
Instead of writing multiple functions at once, you should write one function and ensure it works properly. By the way, the loop that split a number into digits could also be a function.
Try the function with small number (ex. 12 or 21)
Use better name for your variable. arrn and temp are not very clear. original and sorted might be better.
Your length function has a very obvious bug in it. What value does l start with? You don't initialise it so it could start with any value and cause undefined behaviour. You should set it to 0.
int length(int n)
{
int l = 0;
while (n!=0)
{
n=n/10;
l++;
}
return l;
}
Personally, I wouldn't be sorting or reading it into an int - to enable handling leading zeros in the digit string. For example:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXNUMLEN 200
int main(void)
{
int i, j, l, x=0;
char numin[MAXNUMLEN], numout[MAXNUMLEN];
int digits[10]={0};
printf("enter a string of digits: " );
fgets(numin, sizeof(numin), stdin);
printf("\nsaw : %s", numin );
// walk string once, counting num of each digit present
l=strlen(numin);
for(i=0; i<l; i++) {
if( isdigit(numin[i]) ) {
int d = numin[i] - '0'; // char digit to int digit
digits[d]++;
}
}
// for each digit present, write the number of instances of the digit to numout
for( i=0; i<10; i++ ) {
for(j=0; j<digits[i]; j++)
numout[x++] = '0'+i; // int digit back to char digit
}
numout[x]='\0'; // terminate string
printf("sorted: %s\n", numout );
}
Sample run:
watson:digsort john$ ./ds
enter a string of digits: 002342123492738234610
saw : 002342123492738234610
sorted: 000112222233334446789
watson:digsort john$

How to use divide and conquer and the fact that if one subarray has a majority, the combined array has a majority to find majority element?

In the question we were told that the crux of the algorithm is the fact that
"When we get down to single elements, that single
element is returned as the majority of its (1-element) array. At every other level, it will get return values from its
two recursive calls. The key to this algorithm is the fact that if there is a majority element in the combined array,
then that element must be the majority element in either the left half of the array, or in the right half of the array."
My implementation was this, probably very buggy but the general idea was this:
#include <stdio.h>
int merge(int *input, int left, int middle, int right, int maj1, int maj2)
{
// determine length
int length1 = middle - left + 1;
int length2 = right - middle;
// create helper arrays
int left_subarray[length1];
int right_subarray[length2];
// fill helper arrays
int i;
for (i=0; i<length1; ++i)
{
left_subarray[i] = input[left + i];
}
for (i=0; i<length2; ++i)
{
right_subarray[i] = input[middle + 1 + i];
}
left_subarray[length1] = 100;
right_subarray[length2] = 100;
//both return majority element
int count1 = 0;
int count2 = 0;
for (int i = 0; i < length1; ++i) {
if (left_subarray[i] == maj1) {
count1++;
}
if (right_subarray[i] == maj1) {
count1++;
}
}
for (int i = 0; i < length2; ++i) {
if (right_subarray[i] == maj2) {
count2++;
}
if (left_subarray[i] == maj2) {
count2++;
}
}
if (count1 > ((length1+length2) - 2)/2){
return maj1;
}
else if (count2 > ((length1+length2) - 2)/2){
return maj2;
}
else
return 0;
}
int merge_sort(int *input, int start, int end, int maj1, int maj2)
{
//base case: when array split to one
if (start == end){
maj1 = start;
return maj1;
}
else
{
int middle = (start + end ) / 2;
maj1 = merge_sort(input, start, middle, maj1, maj2);
maj2 = merge_sort(input, middle+1, end, maj1, maj2);
merge(input, start, middle, end, maj1, maj2);
}
return 0;
}
int main(int argc, const char* argv[])
{
int num;
scanf("%i", &num);
int input[num];
for (int i = 0; i < num; i++){
scanf("%i", &input[i]);
}
int maj;
int maj1 = -1;
int maj2 = -1;
maj = merge_sort(&input[0], 0, num - 1, maj1, maj2);
printf("%d", maj);
return 0;
}
This obviously isn't divide and conquer. I was wondering what is the correct way to implement this, so I can have a better understanding of divide and conquer implementations. My main gripe was in how to merge the two sub-array to elevate it to the next level, but I am probably missing something fundamental on the other parts too.
Disclaimer: This WAS for an assignment, but I am analyzing it now to further my understanding.
The trick about this particular algorithm, and why it ends up O(n log n) time is that you still need to iterate over the array you are dividing in order to confirm the majority element. What the division provides is the correct candidates for this iteration.
For example:
[2,1,1,2,2,2,3,3,3,2,2]
|maj 3| maj 2
maj 2 | maj None
<-------------------> still need to iterate
This is implicit in the algorithm statement: "if there is a majority element in the combined array, then that element must be the majority element in either the left half of the array." That "if" indicates confirmation is still called for.

Permutations in lexicographical order with not unique characters

I want to make function to output all possible permutations from input string, in lexicographical order.
I have the following code:
void permutations_print(char *permutations, int index, int length) {
if (index == length) {
printf("\"%s\"\n", permutations);
}
for (int i = index; i < length; i++) {
rotate(permutations, i, index);
permutations_to_array(permutations, index + 1, length);
rotate_back(permutations, index, i);
}
}
void rotate(char to_swap[], int i, int j) {
char temp = to_swap[i];
for (int k = i; k > j; k--) {
to_swap[k] = to_swap[k - 1];
}
to_swap[j] = temp;
}
void rotate_back(char to_swap[], int i, int j) {
char tmp = to_swap[i];
for (int k = i; k < j; k++) {
to_swap[k] = to_swap[k + 1];
}
to_swap[j] = tmp;
}
The input string permutations is permutations_print is sorted.
It works without any issues for permutations with just unique characters, but I need it to work also for character non-unique strings, any ideas how to tweak it / modify it / to work? I have to use recursion and should not use any kind of sorting and I should not store it in any array, just print. And I want to print all, even duplicates.
Warning: not a C programmer, so my code can definitely be improved.
You can do it iteratively with something like this:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
void swap(char* array, int i, int j);
void reverse(char* array, int left, int right);
bool nextPermutation(char* array, int n);
int compareCharacters(const void * a, const void * b);
void printPermutations(char *permutations, int length);
int main() {
char myArray[] = "hey";
printPermutations(myArray, 3);
return 0;
}
void printPermutations(char *array, int length) {
qsort(array, length, sizeof(char), compareCharacters);
*(array + length) = '\0';
do {
printf("%s\n", array);
} while (nextPermutation(array, length));
}
int compareCharacters(const void * a, const void * b) {
return (*(char*)a - *(char*)b);
}
bool nextPermutation(char* array, int n) {
if (n <= 1) {
return false;
}
// Find index, swapIndex1, of rightmost number that has a number greater than it
int swapIndex1;
for (swapIndex1 = n - 2; swapIndex1 >= 0; --swapIndex1) {
if (array[swapIndex1] < array[swapIndex1 + 1]) {
break;
}
}
if (swapIndex1 == -1) {
return false;
}
// Find index, swapIndex2, of smallest number to the right of that and greater than it
int swapIndex2 = swapIndex1 + 1;
int minToRight = array[swapIndex2];
for (int i = swapIndex2 + 1; i < n; ++i) {
if (array[i] <= minToRight && array[i] > array[swapIndex1]) {
minToRight = array[i];
swapIndex2 = i;
}
}
// Swap values at swapIndex1 and swapIndex2
swap(array, swapIndex1, swapIndex2);
// Reverse values from swapIndex1+1 to n-1
reverse(array, swapIndex1 + 1, n - 1);
return true;
}
void swap(char* array, int i, int j) {
char temp = array[i];
array[i] = array[j];
array[j] = temp;
}
void reverse(char* array, int left, int right) {
for (; left < right; ++left, --right) {
swap(array, left, right);
}
}
The algorithm is described here. See the comments section for an example/explanation, or see transcription below:
Let's pretend we're finding the next largest permutation of digits from 1-9.
For example, suppose we have: 123479865
We want to find the smallest number greater than 123479865 that can be obtained by rearranging the digits of 123479865.
What this means is that we have to make at least one digit bigger than it currently is. If we had our choice, we would want to make the rightmost digit bigger since that will result in the smallest change. If we were to make a left number bigger, it would result in a bigger change in value.
e.g.: 123479865 => 123479866 is a much smaller change than 123479865 => 223479865.
Therefore, we want to find the farthest digit to the right that we can make bigger. In order to make a digit bigger, we have to find another number bigger than it within our sequence and then swap the two.
Note: we cannot swap a number (e.g., 5) with a number to its left (e.g., 6), because then we would be decreasing the value of a digit to our left, which would make our overall number smaller. For example, if we swapped 5 with 6, we would get 123479856, which is smaller than 123479865. Thus, we always swap with a number to our right.
So let's go through 123479865, starting with the rightmost digit.
There is nothing bigger than 5 to the right of 5, so we can't make 5 bigger.
Now let's consider 6. There is nothing bigger than 6 to the right of 6, so we can't make 6 bigger.
Now let's consider 8. There is nothing bigger than 8 to the right of 8, so we can't make 8 bigger.
Now let's consider 9. There is nothing bigger than 9 to the right of 9, so we can't make 9 bigger.
Now let's consider 7. There are a few numbers to the right of 7 that are bigger than 7, namely: 9 and 8. Therefore, we can make 7 bigger. We want to make it bigger by the least amount, so we should swap it with the smallest value that is bigger than 7. In other words, we should swap 7 with 8. That gives us: 123489765.
The number 123489765 is bigger than 123479865, but we can actually make it smaller while maintaining that it's bigger than 123479865. We can do this because we now have infinite freedom to change any of the following digits: 123489765 (anything to the right of 8). Those numbers can be as small as possible because the 8 to their left ensures that the new number is always bigger.
The best way to make the digits 9765 smaller is to sort them in increasing order, giving us 5679. Sorting works because the leftmost place values contribute the most to the overall value. Therefore, we want the leftmost digits to be the smallest digits.
That leaves us with 123485679, which is our answer.
Note: we don't actually have to sort the numbers to the right of 8. We can actually reverse their order because we know that the numbers from the right side to 8 are in increasing order (because earlier, we stopped the first time we got to a number that was smaller than its previous number).

Resources