Created
June 26, 2013 20:00
-
-
Save donaldguy/5871073 to your computer and use it in GitHub Desktop.
Semi-efficient heavy integer counter in C and Ruby for a code interview. The ruby is admittedly not very idiomatic (hence why I rewrote in C)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// main.c | |
// heavy_numbers | |
// | |
// Created by Donald Guy on 6/18/13. | |
// Copyright (c) 2013 Donald Guy. All rights reserved. | |
// | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <math.h> | |
typedef char int8; | |
/* | |
* Set BCD buffer to next multiple of 10 and return the number of carries required | |
*/ | |
int set_to_nearest_ten(int8* digits, int num_digits) { | |
int num_carries = 1; | |
digits[num_digits - 1] = 0; | |
int i = num_digits - 2; | |
for (;;) { | |
digits[i] += 1; | |
if (digits[i] > 9) { | |
num_carries++; | |
digits[i--] = 0; | |
} else { | |
break; | |
} | |
} | |
return num_carries; | |
} | |
/* | |
* adjust left and right of inequality for the given number of carries, return number of digits | |
*/ | |
int adjust_for_carries(int* left, int* right, int num_carries, int current_digits) | |
{ | |
*left -= 9*num_carries - 1; | |
if (num_carries > current_digits) { | |
*right += 7; | |
return current_digits + 1; | |
} else { | |
return current_digits; | |
} | |
} | |
int solution(int a, int b) { | |
int total_digits = ceil(log10(b)); | |
int current_digits = ceil(log10(a)); | |
int current_value = a; | |
int8* digits = (int8*) malloc(total_digits * sizeof(int8)); | |
int fill_index = total_digits - 1; | |
while (a > 0) { | |
digits[fill_index] = a % 10; | |
a /= 10; | |
fill_index--; | |
} | |
int left = 0; | |
for (int i = total_digits - current_digits; i < total_digits; i++) { | |
left += digits[i]; | |
} | |
int right = current_digits * 7; | |
int total_heavy = 0; | |
while (current_value <= b) { | |
if (left > right) { | |
int distance_to_ten = 10 - digits[total_digits - 1]; | |
// all values from here to next multiple of ten (noninclusive) are heavy | |
// so count them | |
total_heavy += distance_to_ten; | |
//move the loop control to match, but do so before we update digits | |
current_value += distance_to_ten; | |
// then update BCD buffer to that value and do bookeeping | |
int num_carries = set_to_nearest_ten(digits, total_digits); | |
//account for skipped values, if any | |
left += distance_to_ten - 1; | |
current_digits = adjust_for_carries(&left, &right, num_carries, current_digits); | |
} else { | |
current_value++; | |
if (digits[total_digits - 1] == 9) { | |
int num_carries = set_to_nearest_ten(digits, total_digits); | |
current_digits = adjust_for_carries(&left, &right, num_carries, current_digits); | |
} else { | |
digits[total_digits - 1] += 1; | |
left++; | |
} | |
} | |
} | |
if (current_value > b) { | |
int overshoot_amount = current_value - (b+1); | |
total_heavy -= overshoot_amount; | |
} | |
free(digits); | |
return total_heavy; | |
} | |
int main(int argc, const char * argv[]) | |
{ | |
printf("%d", solution(8675, 8689)); | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# avg > 7 | |
# sum / num > 7 | |
# sum > 7*num | |
# left > right | |
# X[1-8] --> X[2-9] ---> left+1 | |
# X[9]n --> (X+1)[0]n --> left-9*n+1 | |
# [9]n --> 1[0]n --> left-9*n+1, right+7 | |
def solution(a,b) | |
total_digits = Math.log(b,10).ceil | |
current_digits = Math.log(a,10).ceil | |
increment_left = b - a | |
digits = Array.new(total_digits) | |
fill_index = total_digits - 1 | |
while a > 0 | |
digits[fill_index] = a % 10 | |
a /= 10 | |
fill_index -= 1 | |
end | |
left = digits.inject(&:+) | |
right = current_digits*7 | |
total_heavy = 0 | |
while increment_left >= 0 | |
if left > right | |
distance_to_carry = 10 - digits[-1] | |
total_heavy += distance_to_carry | |
increment_left -= distance_to_carry | |
num_carries = do_carries(digits) | |
left += distance_to_carry - 1 | |
left -= 9*num_carries - 1 | |
if num_carries > current_digits | |
current_digits += 1 | |
right += 7 | |
end | |
else | |
increment_left -= 1 | |
if digits[-1] == 9 | |
num_carries = do_carries(digits) | |
left -= 9*num_carries - 1 | |
if num_carries > current_digits | |
current_digits += 1 | |
right += 7 | |
end | |
else | |
left += 1 | |
digits[-1] += 1 | |
end | |
end | |
end | |
if increment_left < 0 | |
total_heavy += increment_left + 1 | |
end | |
total_heavy | |
end | |
def do_carries(digits) | |
num_carries = 1 | |
digits[-1] = 0 | |
index = digits.length - 2 | |
loop do | |
digits[index] += 1 | |
if digits[index] > 9 | |
num_carries += 1 | |
digits[index] = 0 | |
index -= 1 | |
else | |
break | |
end | |
end | |
num_carries | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment