O(1) code to count multiples of a number in a range? - c

How do I do this in constant time (I do not want to brute for iterate from a to b)?
// return number of multiples of c in [a,b]
long count_multiples(int a, int b, int c) {
assert(b >= a && c != 0);
// todo
return -1;
}
This question looks deceptively simple but is harder than it looks because it has some corner cases e.g. must handle all cases (a,b can be negative/zero and c can be negative too and a may equal b may equal c). The result may not fit in 32-bit for one case (a = 2^31, b = 2^31-1, c = 1 or -1)

long count_multiples(int a, int b, int c) {
if (b < a) return 0;
if (c < 0) c = -c;
long al = a, bl = b, cl = c;
if (c == 1) return bl - al + 1;
return ((bl + (b < 0 ? 1 : 0)) / cl) -
((al - (a > 0 ? 1 : 0)) / cl) +
((a <= 0 && b >= 0) ? 1 : 0);
}

Related

Sorting 3 variables in C just does not work

#include <stdio.h>
int main(void) {
int a = 0, b = 0, c = 0,
total = 0, helper = 0, helper_2 = 0, helper_3 = 0;
scanf("%d%d%d%d", &total, &a, &b, &c);
helper = (a <= b && a <= c ? a : (b <= c ? b : c));
helper_2 = (c >= b && a >= c ? c : (b >= a && a >= c ? a : (c >= b && b >= a ? b : 0)));
helper_3 = (a >= b && a >= c ? a : (b >= c ? b : c));
if ((total < 0) || (total > 1000) || (helper <= 0) ||
(helper_2 <= 0) || (helper_3 <= 0) || (helper > 1000) ||
(helper_2 > 1000) || (helper_3 > 1000)) {
printf("0");
return 0;
}
else if ((helper + helper_2 + helper_3) <= total) {
printf("3");
}
else if (helper + helper_2 <= total) {
printf("2");
}
else if (helper <= total) {
printf("1");
}
else {
printf("0");
}
return 0;
}
That is the code. I sort three variables, and store them in 3 different variables according to their size, the small one goes to the first one and so on...
The thing is, all the variables MUST be between 0 and 1001.
It seems to work well, but it does not. It has errors but I cannot find them. I just would like to know if some of you guys can help me to improve this code or even tell me what inputs to use that would return an unexpected value.
Thanks so much:D
Edit: I fixed part of them by removing the 0 from the helper_2 expression:D it would return 0 if the input would be for ex: 6, 1, 3, 2.
EDIT2: I've already answered it how you solve using ternary, but the other answers are so much better than the one I was using. So, thank you so much for everyone who helped me:D
The expression:
helper_2 = (c >= b && a >= c ? c : (b >= a && a >= c ? a : (c >= b && b >= a ? b : 0)));
is wrong. The last part can return zero! That's a bug. When we know that a, b and c are all greater than zero, the result just can't be zero.
Try input a=1, b=3, c=2 and print the value of the helper variables.
int a = 1;
int b = 3;
int c = 2;
int helper_1 = (a <= b && a <= c ? a : (b <= c ? b : c));
int helper_2 = (c >= b && a >= c ? c : (b >= a && a >= c ? a : (c >= b && b >= a ? b : 0)));
int helper_3 = (a >= b && a >= c ? a : (b >= c ? b : c));
printf("%d %d %d --> %d %d %d\n", a, b, c, helper_1, helper_2, helper_3);
Output:
1 3 2 --> 1 0 3
which is obviously wrong
My advice is to avoid the complex ternary conditionals. Write simple if statements instead.
For instance:
if (a > b)
{
// swap a and b
}
if (a > c)
{
// swap a and c
}
if (b > c)
{
// swap b and c
}
// Now a, b and c is sorted with a being smallest
You could really use a few helper functions to clean up your code.
One function to "swap" a pair of variables if the first is greater than the second:
void Sort2(int* x, int* y) {
if (*x > *y) {
int tmp = *x;
*x = *y;
*y = tmp;
}
}
Another to validate a range:
int isInRange(int minimum, int maximum, int value) {
return ((minimum <= value) && (value <= maximum));
}
Then your code gets really simple:
int main(void) {
int a = 0, b = 0, c = 0,
total = 0;
scanf("%d%d%d%d", &total, &a, &b, &c);
Sort2(&a, &b);
Sort2(&a, &c);
Sort2(&b, &c);
// a,b, and c are in sorted order
if !(isInRange(0, 1000, total) && isInRange(1, 1000, a) && isInRange(1, 1000, b) && isInRange(1, 1000, c))
{
printf("0");
return 0;
}
if ((a + b + c) <= total) {
printf("3");
}
else if (a + b <= total) {
printf("2");
}
else if (a <= total) {
printf("1");
}
else {
printf("0");
}
return 0;
}
Just remove helper_2 condition and use:
a>b? ( c>a? a : (b>c? b:c) ) : ( c>b? b : (a>c? a:c) ) )
instead. :D

Recursion algorithm for relatively prime integers

I'm making a function that checks if 2 integers are relatively prime / coprime. The function returns 1 if they are relatively prime and 0 if they are not relatively prime.
The function should be able to accept any integer in any order, given that a and b are both not 0;
To my knowledge having a gcd of -1 is the same as having a gcd of 1. Is that correct?
This is my code:
int relatively_prime(int a, int b){
if (a == 0 || b == 0) return 0;
if (a%b == 0 && (b != 1 || b != -1)) return 0;
else if (a%b== 0 && (b == 1 || b == -1)) return 1;
else return relatively_prime(b, a % b);
}
Is this correct? Is there any way to simplify or improve my code?
Thanks!
int gcd(int a, int b)
{
a=abs(a);
b=abs(b);
if (b == 0)
return a;
return gcd(b, a % b);
}
Now if the result is 1 they are coprime . You can convert negative number into positive to see if they are co prime and simplify the code .Technically speaking we can write 0 as 0* any number so 0 will not be co prime with any number other than 1 .
Is this correct?
No.
b != 1 || b != -1 is always true. So code is like
int relatively_prime(int a, int b){
if (a == 0 || b == 0) return 0;
if (a%b == 0 /* && (b != 1 || b != -1) */) return 0;
// a%b== 0 is never true below after the above line
// else if (a%b== 0 && (b == 1 || b == -1)) return 1;
else return relatively_prime(b, a % b);
}
... and does not return 1.
OP's code fails with undefined behavior (UB) at least with the case of relatively_prime(INT_MIN, -1) as it attempts INT_MIN % -1.
Is there any way to simplify ?
// Do not call with gcd_recursive(INT_MIN, -1)
static int gcd_recursive(int a, int b) {
if (b == 0) return a;
return gcd_recursive(b, a % b);
}
int relatively_prime_alt(int a, int b) {
if (b == -1) b = 1; // Avoid a INT_MIN % -1 in gcd_recursive()
int gcd = gcd_recursive(a, b);
return gcd == 1 || gcd == -1;
}

Connect Four Check Winner

So to change my question. It refuses to recognize that there are four twos in a row. It recognizes that there are four ones in a row but that happens after the four twos. Why is this happening?
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 1 1 1 1 0 0
1 2 2 2 2 0 0
int checkFour(int a, int b, int c, int d){
if (a == b == c == d){
return 1;
}
else{
return 0;
}
return 0;
}
//check for the horizontal win
int checkHorizontal(){
for(int i=0; i < rows; i++){
for(int j=0; j < column - 3; j++){
if ((board[i][j] != 0) && (board[i][j+1] != 0) && (board[i][j+2]!= 0) && (board[i][j+3] != 0)){
if (checkFour(board[i][j],board[i][j+1],board[i][j+2],board[i][j+3]) == 1){
printf("Game Over\n");
exit(0);
}
}
}
}
}
What am I doing wrong?
if (a == b == c == d){ does not work the way you might think. The result of a comparison in C is a boolean value of 0 or 1. Given that == operator has left-to-right associativity, your statement can be re-written as:
if ((((a == b) == c) == d)
This appears to give correct results when they are all 1. This is because it ends up comparing the values (1) to the result of the comparison operation, also (1).
(((a == b) == c) == d) a == b -> 1
((1 == c) == d) 1 == c -> 1
(1 == d) 1 == d -> 1
The correct way is to use logical AND.
if (a == b && a == c && a == d)
All three comparisons need to evaluate to true for the entire statement to be true.
Note that there are other combinations that work. Ex:
if (a == b && b == c && c == d)
By the way, you can shorten the entire function to
int checkFour(int a, int b, int c, int d){
return a == b && b == c && c == d;
}
The problem is that you misunderstood the mechanism of C. the code if (a == b == c == d) wouldn't take if abcd are all values equal then return 1. because C computes from left to right(same priority), so it would compute a == b first, the result is 1 or 0, then take this result to compare with c, the second result also is 1 or 0, finally take second result to compare with d and the final result is come out.
The right code is like this:
if ((a == b) && (d == c) && (b == c))
return 1;
else
return 0;

Optimizing a nested loop in C

I have a nested loop to find all possible combinations of numbers between 1 and x in groups of 4, where a < b < c < d.
A method is called as each group is discovered to do a simple equivalency test on the sum of those numbers.
The loop does work and produces expected output (1 set of numbers for this particular x), however it takes 12+ seconds to find this answer and another ~5 to test the remaining possibilities, which is definitely bad, considering the x values are < 1000.
I tried having the outer loop iterate a < x - 3 times, the b loop b < x - 2 times, down to d < x times which didn't make a noticeable difference.
What would be a better approach in changing this loop?
for (a = 1; a < x; a++) {
for (b = a + 1; b < x; b++) {
for (c = b + 1; c < x; c++) {
for (d = c + 1; d < x; d++) {
check(a, b, c, d);
}
}
}
}
With such a deep level of nesting, any early exit you can introduce - particularly at the outer loops - could net big gains.
For example, you write that check is testing a + b + c + d == x && a * b * c * d == x - so you can compute the intermediate sum and product, and break when you encounter numbers that would make any selection of later numbers impossible.
An example:
for (a = 1; a < x; a++) {
for (b = a + 1; b < x; b++) {
int sumAB = a + b;
if (sumAB + sumAB > x) break;
int prodAB = a * b;
if (prodAB * prodAB > x) break;
for (c = b + 1; c < x; c++) {
int sumABC = sumAB + c;
if (sumABC + c > x) break;
int prodABC = prodAB * c;
if (prodABC * c > x) break;
for (d = c + 1; d < x; d++) {
int sumABCD = sumABC + d;
if (sumABCD > x) break;
if (sumABCD != x) continue;
int prodABCD = prodABC * d;
if (prodABCD > x) break;
if (prodABCD != x) continue;
printf("%d, %d, %d, %d\n", a, b, c, d);
}
}
}
}
This is just an example - you can constrain all the checks here further (e.g. make the first check be sumAB + sumAB + 3 > x). The point is to focus on early exits.
I added a counter for each loop, counting how many times it was entered, and tried your version and my version, with x = 100. My version has orders of magnitude less loop entries:
No early exits: 99, 4851, 156849, 3764376
With early exits: 99, 4851, 1122, 848

Including first iteration in loop in C

I wrote this program to give the user all acute triangle solutions when they give a min and max value. It works correctly except it seems like the solutions don't include the first iterations of the loops (for example, with min = 1 and max = 45, (1, 1, 1) isn't included in the solutions). How can this be fixed? I thought the problem was with my while-loop for the a-value, but when I changed it into a for-loop, the problem persisted. How can I have it include these first values?
if (c >= dmin) {
c = dmin;
do {
++c;
for (b = dmin; b < dmax; b++) {
a = dmin;
while (a < dmax) {
a = a + 1;
if (a * a + b * b - c == c * c) {
if (((a + b) > c) && ((b + c) > a) && ((c + a) > b)) {
printf("(%d, %d, %d)", a, b, c);
}
}
}
}
} while (c <= dmax);
}
move ++c; after the for loop instead of before.
This increments c to 2 before it even starts, but you want to include 1.
*Note, you may want to add conditions that prevent minimums of 0 or less.
If the value range for a, b and c is [dmin..dmax] (both inclusive), the sample looks like below:
for (c = dmin; c <= dmax; c++)
{
for (b = dmin; b <= dmax; b++)
{
for (a = dmin; a <= dmax; ++a)
{
if (a * a + b * b - c == c * c )
{
if (((a + b) > c) && ((b + c) > a) && ((c + a) > b))
{
printf("(%d, %d, %d)", a, b, c);
}
}
}
}
}

Resources