I got a task for hw to make a recursive function that checks between 2 unsigned long long numbers and check for common digits if there is its will print the common digits (its starts checking from right to left- when a match found we stop and print that digit)
if there is no same digits its will return -1
The problem is I could make it work for the first and last example but I am having trouble dealing with the second example.
any hints will be appreciated :)
```c
int findCommonDigit(unsigned long long n1, unsigned long long n2) {
int temp1 = 0, temp2 = 0;
if (n1 == 0 || n2 == 0)
return -1;
temp1 = n1 % 10;
temp2 = n2 % 10;
if (temp1 == temp2)
return temp1;
return findCommonDigit(n1 / 10, n2 / 10);
}
So, the task, as I understand it, is to determine whether or not two numbers share at least one digit. Constraints are:
Scan right to left.
In the case of (21, 12) return 1, not 2. (As per your commentary.)
The solution should be a recursive function.
Right-O. So, the trick is to compare every digit in the first number with every digit in the second number. There are quite a few ways to optimize this, but we will stick with an O(n²) brute-force method.
Given 123 and 456:
compare 3 with 6
compare 3 with 5
compare 3 with 4
compare 2 with 6
compare 2 with 5
compare 2 with 4
compare 1 with 6
compare 1 with 5
compare 1 with 4
Hopefully you can see that that was a nested loop:
for each digit in N1:
for each digit in N2:
match?
Conveniently, getting the rightmost (“least-significant”) digit value is a simple remainder operation:
int digit = number % 10;
After that we modify the number to shift all the digit places down one using integer division:
number = number / 10;
We want to use recursion (instead of a looping construct like while or for), so we need to transform each one of those loops into a recursive function call.
Basic Recursion
A recursive function works by having one or more termination conditions. Failing the termination condition, it just calls itself with updated arguments.
For simple example, we can take a counting loop:
void print_START_to_STOP( int start, int stop )
{
for (; start < stop; start = start+1)
printf( "%d\n", start );
}
And make it recursive:
void print_START_to_STOP( int start, int stop )
{
if (!(start < stop)) return; // termination condition
printf( "%d\n", start ); // (loop body)
print_START_to_STOP( start+1, stop ); // invoke next iteration
}
Take a few minutes to convince yourself that those two functions are equivalent. One uses an explicit loop. One uses recursion.
Inner Loop
Let’s start easy and work on a recursive function for the inner loop:
bool isDigitInNumber( int digit, unsigned long long number )
{
...
}
As recursion needs at least one termination condition, the first thing to check is if there are any digits left in number to check against the argument digit. If not, there is no match.
if (number == 0) return false;
The next thing to do is check to see if the least-significant digit of number matches the digit. If it does, we have another termination condition:
if ((number % 10) == digit) return true;
Otherwise we are left needing to check the remaining digits in number. This is where we invoke recursion:
return isDigitInNumber( digit, number/10 );
Zero?
You might ask, “What if digit is 0 and number has a 0 in it?”
Give it a try. Does it work for number == 201?
“Okay, so what if digit is 0 and number is also 0?”
That is a good question. Should findCommonDigit( 0, 0 ) return 0 or -1?
(Chances are your professor expects findCommonDigit( 0, 0 ) to return -1. I personally think it would be more correct if it returned 0. The only thing that shouldn’t return 0 is if either one of the numbers does not have an embedded zero, such as 123 and 456, and 0 and 123.)
Let’s come back to this in a minute.
Reflection
Let’s think about what we’ve done to simplify our problem:
isDigitInNumber( 3, 456 )
isDigitInNumber( 2, 456 )
isDigitInNumber( 1, 456 )
If any one of those is true, then we can return the matching digit. Otherwise we return -1.
You should also notice that there is still an outer loop to conquer.
Outer Loop
For the outer loop, we can create a new recursive function that makes use of the last recursive function.
Take a second and think about what this recursion is looping over: N1.
Just as the last function loops over N2 and gets the digit-to-compare by using remainder on N2, this recursive function loops over N1 and gets the digit-to-compare by using remainder on N1:
int digit_to_compare = n1 % 10;
Again we need some termination conditions and a recursion.
When do we stop and return -1?(After looping through all digits of N1 and not finding a match using isDigitInNumber().)So... when N1 is zero we are done. No match. Return -1.
if (n1 == 0) return -1;
Otherwise we need to try to match the digit-to-compare with all the digits in N2:
if (isDigitInNumber( digit_to_compare, n2 )) return digit_to_compare;
And finally, the digit wasn’t matched, we need to recurse on the next digit in N1:
return findCommonDigit( ... );
You are basically done.
Zero Redux
Now back to that tricky question about zeros.
Remember that the inner-loop algorithm could not check for the possibility of zero matching zero. But that’s okay. It wasn’t the right place to check.
The right place is before you do any loops at all. Right at the beginning of your algorithm, check to see if N1 == N2. If it does, then the rightmost digit of both numbers is the same. Even if both numbers are zero.
int findCommonDigit( ... )
{
if (n1 == n2) return (n1 % 10); // return the matching digit, which might be 0
return findCommonDigit_Impl( n1, n2 );
}
You will have had to rename the last findCommonDigit() function to findCommonDigit_Impl(), of course.
So many functions! What the double-hockeysticks?!
In order to handle the special condition of zeros we had to add yet another function to the mix.
That is kind of unavoidable. Otherwise we can’t tell the difference between findCommonDigit( 123, 0 ) and findCommonDigit( 0, 0 ), and the result differs between ( 123, 0 ) and ( 0, 123 ).
Anyway, we now have have three functions:
bool isDigitInNumber( int digit, unsigned long long number );
int findCommonDigit_Impl( unsigned long long n1, unsigned long long n2 );
int findCommonDigit( unsigned long long n1, unsigned long long n2 );
The last one is the one that gets invoked by the user:
int main(void)
{
printf( "%d\n", findCommonDigit( 1234, 2 ) );
The other two are the recursive functions, and do not get invoked by the user.
It is entirely possible to combine these all into a single recursive function.
Don’t waste your time though. Doing that increases complexity, and you would have to add additional formal arguments to deal with it. (Or use global variables or some other Don’t-Do-That-Crufty hack.)
It is entirely okay to have useful helper functions. And when dealing with recursion, this kind of multiple-function structure is actually very common and normal.
Hopefully this wasn’t too long-winded, nor gave away the answer too easily. Much of the time spent here was to help think your way through designing a recursive algorithm, so that when you have to do it again in the future you won’t be utterly lost. (Recursion is hard!)
AAAANNNND, hopefully your classmates will get it too, but without producing an exact copy of you code, lol. Professors want you to learn, not cheat off the internet, and I’ve made this fairly easy to draw that kind of conclusion, alas.
P.S
BTW, you might get away with using a loop inside your recursive function: an explicit inner loop for the digits of N2 and recursion for the outer loop over N1. IDK if that is acceptable. This answer assumes no loops allowed.
You can use a loop based function instead like following:
int findCommonDigit(unsigned long long n1, unsigned long long n2) {
int digitN1[11] = {0}, digitN2[11] = {0};
while(n1) {
int x = n1 % 10;
n1 /= 10;
digitN1[x] = 1;
}
while(n2) {
int x = n2 % 10;
n2 /= 10;
digitN2[x] = 1;
}
for(int i=0; i<10; i++) {
if(digitN1[i] && digitN2[i]) {
return i;
}
}
return -1;
}
Here digitN1 and digitN2 are two flag arrays used to store whether digits[0..9] are set on numbers n1 and n2 respectively. Then we use a for loop to check whether any digit is on both numbers or not. If no common digits found, -1 is returned.
You can write a while loop until "n2 > 0" in main function. For every digit you will call "findCommonDigit" function and check is the return value is -1 or not. If you get a digit that is not -1 then print it and break the While loop. After the while loop you can write printf("-1").
For that you have to change this return findCommonDigit(n1 / 10, n2 / 10); to this return findCommonDigit(n1 / 10, n2);
Otherwise you can change your function to this,
int findCommonDigit(unsigned long long n1, unsigned long long n2) {
int temp1 = 0, temp2 = 0;
if (n1 == 0 || n2 == 0){
return -1;
}
temp1 = n1 % 10;
temp2 = n2 % 10;
if (temp1 == temp2){
return temp1;
}
n1 /= 10;
return findCommonDigit(n1, n2);
n2 /= 10;
return findCommonDigit(n1, n2);
}
This is what I came up with based on your and my test cases.
Twice the recursion twice the fun!
#include <stdio.h>
#define DEBUG_FUNCTION 0
int compareN1Digits(unsigned long long n1, unsigned long long n2)
{
int n1RightDigit = n1 % 10;
if(DEBUG_FUNCTION) printf(" n1 right most digit : %d\n", n1RightDigit);
int result = -1;
if (n1RightDigit != n2)
{
if(DEBUG_FUNCTION) printf("Not a match.\n");
if (n1 > 10)
{
result = compareN1Digits(n1 / 10, n2);
}
}
else
{
result = n1RightDigit;
}
return result;
}
int findCommonDigit(unsigned long long n1, unsigned long long n2)
{
int n2RightDigit = n2 % 10;
if(DEBUG_FUNCTION) printf("n2 right most digit : %d\n", n2RightDigit);
int result = -1;
result = compareN1Digits(n1, n2 % 10);
if (result == -1)
{
if (n2 >= 10)
{
result = findCommonDigit(n1, n2 / 10);
}
}
return result;
}
void RunTestCase(unsigned long long n1, unsigned long long n2, int expectedResult)
{
int result;
result = findCommonDigit(n1, n2);
if (result == expectedResult)
{
printf("Corrent Result\n\n");
}
else
{
printf("Result NOT corrent!\n\n");
}
}
int main()
{
// Test Case 1
// 22222446, 113355578889 => function will give back -1
RunTestCase(22222446, 113355578889, -1);
// Test Case 2
// 13259438, 2 => function will give back 2
RunTestCase(13259438, 2, 2);
// Test Case 3
// 112233445, 112233445 => function will give back 5.
RunTestCase(112233445, 112233445, 5);
// Test Case 4
// 2, 13259438 => function will give back 2
RunTestCase(2, 13259438, 2);
// Test Case 5
// 12034, 567809 => function will give back 0
RunTestCase(12034, 567809, 0);
// Test Case 6
// 1, 1 => function will give back 1
RunTestCase(1, 1, 1);
// Test Case 7
// 0, 0 => function will give back 0
RunTestCase(0, 0, 0);
return 0;
}
Related
int test(int n) {
if(n <= 2)
{
return n;
}
return test(n-1) + test(n-2) + test(n-3);
}
Is there any way to speed it up without changing function declaration, when n becomes larger, it will take plenty of time to get the out put.
0.1.2.3.6.11.20
when n = 3, it should get the out put 0+1+2=3
when n = 5, it should get the out put 2+3+6=11
Imagine you want to find test(10). As a human, you will naturally find the algorithm to find that. Start making a table of results.
n = 0 -- result is 0
n = 1 -- result is 1
n = 2 -- result is 2
To continue the table, just use the last few numbers in the table:
n = 0 -- result is 0
n = 1 -- result is 1
n = 2 -- result is 2
n = 3 -- result is 3
n = 4 -- result is 6
...
The algorithm is "take last 3 numbers and add them, then write the answer in the new line in your table". This is easy to implement. Something like this:
n1 = 2
n2 = 1
n3 = 0
for i from 3 to n
// Imagine you have everything up to i written on paper.
// Here n1 is the last number, n2 is before that, n3 is before that.
// Try to continue writing your table.
result = n1 + n2 + n3
// Now imagine you have written the result on paper.
// What are the 3 last numbers now?
n3 = n2
n2 = n1
n1 = result
// Verify that in a debugger for better visualization.
// Now, after the loop is finished, n1 (the last number) is the correct answer.
return n1
If you want to keep using recursion you have to use memoization, or caching. The idea is, when calculating a result, store it for later.
I suggest having an array of sufficient size, say 100 entries (seeing that the numbers grow just a bit slower than 2n, this should be enough to represent any 64-bit number). Initialize it to 0:
int test(int n)
{
static int cache[100] = {0};
...
}
After calculating a result, store it in the correct index:
int test(int n)
{
...
result = ...
cache[n] = result;
return result;
}
But before applying the formula, check if the cache contains the result:
int test(int n)
{
...
if (cache[n] != 0)
result = cache[n];
...
}
Time to get out the tail recursion hammer
static int testk(int i, int n, int a, int b, int c)
{
if (i == n) return a + b + c;
return testk(i + 1, n, a + b + c, a, b);
}
int test(int n) {
if (n < 2) return n;
return testk(3, n, 2, 1, 0);
}
This is a direct translation of anatolyg's answer to tail recursion.
As you probably figured out, the reason your recursive solution is slow is because you recompute answers that had already been computed before.
This is why memoization works, and it allows you to maintain your top down algorithmic translation of the sequence as mathematically defined.
The disadvantage of complete memoization is that the table can be arbitrarily large. If O(1) time (at the cost of O(n) space) is not required, and O(n) time is sufficient, it is possible to perform the computation with O(1) space, and this has been illustrated in other answers as well.
All that is really required is that for any recursive calculation of test(n-1), the values for test(n-2) and test(n-3) should also be available. If you do not like creating a helper recursive function to track this information, then the below is an alternative that uses a single recursive function.
int test(int n) {
typedef struct { int x[2]; } state;
static const state init = { 0, 1 };
static state last;
if (n > 0) {
last = init;
return test(-n);
}
n = -n;
if (n < 3) return n;
// After the below call, last has test(n-2) and test(n-3)
int x = test(-(n-1));
int result = x + last.x[0] + last.x[1];
last.x[0] = last.x[1];
last.x[1] = x;
return result;
}
Try it online!
While finishing an assignment I had to figure out how to check if the first two numbers of an input are of certain combination. While I have the idea what to do, I seem to have an error in the first part of my code.
I wanted to ''isolate'' the first two numbers by dividing the input by 10 while the input is more than 2.
I wrote this block of code
do
{
card_number = card_number / 10;
}
while (card_number > 2);
I was expecting the result to be '45' for example, but everytime I run the code and use printf to see the result, the only thing coming back is a zero.
If you're trying to isolate the first two digits of card_number, then your condition should check that the length of the number is 2, not the value. Another way to do this is to keep dividing by 10 if the value is greater than 100.
#include <stdio.h>
int main(void) {
int card_number = 450;
printf("%i\n", card_number);
while(card_number > 100) {
card_number = card_number / 10;
}
printf("%i\n", card_number);
return 0;
}
(Since you're trying to isolate the first two digits, I assume the value does start out greater than 100.)
Updated to "isolate" first 2 digits...
I think this is what you're asking ...
int main() {
//TEST CASES = Longer and Shorter than 2 digits
//Comment and uncomment c_num as required for testing both cases
long c_num = 1234567812345678;
//long c_num = 12;
int count = 0;
long n = c_num;
long long n1 = c_num, n2 = c_num; // n2 will hold the first two digits.
while (n) {
n2 = n1;
n1 = n;
n /= 10;
}
printf("The first 2 numbers of the long are %lld\n", n2);
/* Run loop till num is greater than 0 */
do {
/* Increment digit count */
count++;
/* Remove last digit of 'num' */
c_num /= 10;
}
while (c_num != 0);
printf("Total digits: %d\n", count);
if (count > 2) {
/* Do work */
printf("Total digits is more than 2");
} else {
/*Do other work */
printf("Total digits is NOT more than 2");
}
return 0;
}
I am currently trying to write a method which checks how often a number is divisible by 5 with a rest of 0 (e.g. 25 is two times; 125 is three times).
I thought my code is correct but it always states that it is possible one more time than it actually is (e.g. 25 is three times; wrong).
My approach is the following:
int main()
{
div_t o;
int inp = 25, i = 0;
while(o.rem == 0){
o = div(inp, 5);
inp = o.quot;
i++
}
return 0;
}
I debugged the code already and figured that the issue is that it steps once more into the loop even though the rest is bigger 0. Why is that? I can't really wrap my head around it.
First: 25/5 = 5; Rest = 0;
Second: 5/5 = 1; Rest = 1; - Shouldn't it stop here?
Third: 1/5 = 0; Rest = 1;
Ah... got it. The point where the remainder is 0 is reached when the division is done with the number which results in a rest bigger zero which is after i got increased.
What is the cleanest approach to fix that? i -= 1 seems kinda like a workaround and I wanted to avoid using an if to break
You're using div() to do the division, which I had to look up to verify that it's part of the standard. I think it's kind of rarely used, and more suited for cases where you really care about performance. This doesn't seem like such a case, and so I think it's a bit obscure.
Anyhow, here's how I would expect it to look, without div():
#include <stdio.h>
unsigned int count_factors(unsigned int n, unsigned int factor)
{
unsigned int count = 0;
for(; n >= factor; ++count)
{
const int remainder = n % factor;
if(remainder != 0)
break;
n /= factor;
}
return count;
}
int main(void) {
printf("%u\n", count_factors(17, 5));
printf("%u\n", count_factors(25, 5));
printf("%u\n", count_factors(125, 5));
return 0;
}
This prints:
0
2
3
Change the while loop condition in :
while(o.rem == 0 && inp >= 5)
In this way your division will stop after that you are inspecting the number 5.
A suggestion: use a const variable to wrap the 5 ;)
As far as I understand you want to know whether the input is an integer power of 5 (or in general whether v == N^x) and if it is, you want to calculate and return the power (aka x). Otherwise return 0. This is more or less a logN function except that it requires integer results.
I would go for code like this:
#include <stdio.h>
unsigned int logN_special(unsigned int v, unsigned int n)
{
unsigned int r = 0;
if (n == 0) return 0; // Illegal
if (n == 1) return 0; // Illegal
if (v < n) return 0; // Will always give zero
if (n*(v/n) != v) return 0; // Make sure that v = n^x
// Find the x
while(v != 1)
{
v /= n;
++r;
}
return r;
}
Is there any simple way to make this small program faster? I've made it for an assignment, and it's correct but too slow. The aim of the program is to print the nth pair of primes where the difference between the two is two, given n.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
bool isPrime(int number) {
for (int i = 3; i <= number/2; i += 2) {
if (!(number%i)) {
return 0;
}
}
return 1;
}
int findNumber(int n) {
int prevPrime, currentNumber = 3;
for (int i = 0; i < n; i++) {
do {
prevPrime = currentNumber;
do {
currentNumber+=2;
} while (!isPrime(currentNumber));
} while (!(currentNumber - 2 == prevPrime));
}
return currentNumber;
}
int main(int argc, char *argv[]) {
int numberin, numberout;
scanf ("%d", &numberin);
numberout = findNumber(numberin);
printf("%d %d\n", numberout - 2, numberout);
return 0;
}
I considered using some kind of array or list that would contain all primes found up until the current number and divide each number by this list instead of all numbers, but we haven't really covered these different data structures yet so I feel I should be able to solve this problem without. I'm just starting with C, but I have some experience in Python and Java.
To find pairs of primes which differ by 2, you only need to find one prime and then add 2 and test if it is also prime.
if (isPrime(x) && isPrime(x+2)) { /* found pair */ }
To find primes the best algorithm is the Sieve of Eratosthenes. You need to build a lookup table up to (N) where N is the maximum number that you can get. You can use the Sieve to get in O(1) if a number is prime. While building the Sieve you can build a list of sorted primes.
If your N is big you can also profit from the fact that a number P is prime iif it doesn't have any prime factors <= SQRT(P) (because if it has a factor > SQRT(N) then it should also have one < SQRT(N)). You can build a Sieve of Eratosthenes with size SQRT(N) to get a list of primes and then test if any of those prime divides P. If none divides P, P is prime.
With this approach you can test numbers up to 1 billion or so relatively fast and with little memory.
Here is an improvement to speed up the loop in isPrime:
bool isPrime(int number) {
for (int i = 3; i * i <= number; i += 2) { // Changed the loop condition
if (!(number%i)) {
return 0;
}
}
return 1;
}
You are calling isPrime more often than necessary. You wrote
currentNummber = 3;
/* ... */
do {
currentNumber+=2;
} while (!isPrime(currentNumber));
...which means that isPrime is called for every odd number. However, when you identified that e.g. 5 is prime, you can already tell that 10, 15, 20 etc. are not going to be prime, so you don't need to test them.
This approach of 'crossing-out' multiples of primes is done when using a sieve filter, see e.g. Sieve of Eratosthenes algorithm in C for an implementation of a sieve filter for primes in C.
Avoid testing ever 3rd candidate
Pairs of primes a, a+2 may only be found a = 6*n + 5. (except pair 3,5).
Why?
a + 0 = 6*n + 5 Maybe a prime
a + 2 = 6*n + 7 Maybe a prime
a + 4 = 6*n + 9 Not a prime when more than 3 as 6*n + 9 is a multiple of 3
So rather than test ever other integer with + 2, test with
a = 5;
loop {
if (isPrime(a) && isPrime(a+2)) PairCount++;
a += 6;
}
Improve loop exit test
Many processors/compilers, when calculating the remainder, will also have available, for nearly "free" CPU time cost, the quotient. YMMV. Use the quotient rather than i <= number/2 or i*i <= number to limit the test loop.
Use of sqrt() has a number of problems: range of double vs. int, exactness, conversion to/from integer. Recommend avoid sqrt() for this task.
Use unsigned for additional range.
bool isPrime(unsigned x) {
// With OP's selective use, the following line is not needed.
// Yet needed for a general purpose `isPrime()`
if (x%2 == 0) return x == 2;
if (x <= 3) return x == 3;
unsigned p = 1;
unsigned quotient, remainder;
do {
p += 2;
remainder = x%p;
if (remainder == 0) return false;
quotient = x/p; // quotient for "free"
} while (p < quotient); // Low cost compare
return true;
}
#include <stdio.h>
int iscoprime(int num1, int num2);
int main() {
int x;
x = iscoprime( 7, 8 );
printf("%d",x);a
}
int iscoprime(int num1, int num2) {
int r = 0;
int gcd = 0;
int i;
for(i = 0; (i < num1) || (i < num2) ; ++i) {
if( (num1 % i == 0) && (num2 % i == 0)) {
gcd = i;
}
}
if ( gcd == 1 ) r = 1;
return r;
}
Error: this program has stopped..??? :(
Your program has some flaws.
1) The for loop starts with i value 0. So, in the first iteration itself, floating point exception will occur. It should start from 1.
2) Your question stated that the program is finding the gcd. Which doesn't seem to be the matter. It seems to me that it is finding whether the given numbers are co-prime or not.
If its a GCD program, the return statement should be
return gcd; //without the previous if condition
Its unclear what you want your return value to mean from the iscoprime function. It looks like it returns the greatest common divisor and then checks if it is 1, then the two inputs are co-prime, and else it uses r's initial value of 0 hence meaning it will print 1 if the numbers are co-prime and 0 if they are not. Your for loop doesn't quite make sense. The max greatest common divisor of two numbers can have would be the lower of the two values. I would start your for loop at this value, 7 in your case and decrement i with each iteration and return i when both numbers divide by i without a remainder. This would would then be your greatest common divisor, if it is 1, then your two numbers are co-prime.
While this implementation is fine for small numbers, if the numbers are going to be very large, I would have a look at https://en.wikipedia.org/wiki/Euclidean_algorithm which can compute the GCD very fast and the same will still apply, if the GCD is 1, the two inputs are co-prime.