i'm going to learn C++ at the very beginning and struggling with some challenges from university.
The task was to calculate the cross sum and to use modulo and divided operators only.
I have the solution below, but do not understand the mechanism..
Maybe anyone could provide some advice, or help to understand, whats going on.
I tried to figure out how the modulo operator works, and go through the code step by step, but still dont understand why theres need of the while statement.
#include <iostream>
using namespace std;
int main()
{
int input;
int crossSum = 0;
cout << "Number please: " << endl;
cin >> input;
while (input != 0)
{
crossSum = crossSum + input % 10;
input = input / 10;
}
cout << crossSum << endl;
system ("pause");
return 0;
}
Lets say my input number is 27. cross sum is 9
frist step: crossSum = crossSum + (input'27' % 10 ) // 0 + (modulo10 of 27 = 7) = 7
next step: input = input '27' / 10 // (27 / 10) = 2.7; Integer=2 ?
how to bring them together, and what does the while loop do? Thanks for help.
Just in case you're not sure:
The modulo operator, or %, divides the number to its left by the number to its right (its operands), and gives the remainder. As an example, 49 % 5 = 4.
Anyway,
The while loop takes a conditional statement, and will do the code in the following brackets over and over until that statement becomes false. In your code, while the input is not equal to zero, do some stuff.
To bring all of this together, every loop, you modulo your input by 10 - this will always return the last digit of a given Base-10 number. You add this onto a running sum (crossSum), and then divide the number by 10, basically moving the digits over by one space. The while loop makes sure that you do this until the number is done - for example, if the input is 104323959134, it has to loop 12 times until it's got all of the digits.
It seems that you are adding the digits present in the input number. Let's go through it with the help of an example, let input = 154.
Iteration1
crossSum= 0 + 154%10 = 4
Input = 154/10= 15
Iteration2
crossSum = 4 + 15%10 = 9
Input = 15/10 = 1
Iteration3
crossSum = 9 + 1%10 = 10
Input = 1/10 = 0
Now the while loop will not be executed since input = 0. Keep a habit of dry running through your code.
#include <iostream>
using namespace std;
int main()
{
int input;
int crossSum = 0;
cout << "Number please: " << endl;
cin >> input;
while (input != 0) // while your input is not 0
{
// means that when you have 123 and want to have the crosssum
// you first add 3 then 2 then 1
// mod 10 just gives you the most right digit
// example: 123 % 10 => 3
// 541 % 10 => 1 etc.
// crosssum means: crosssum(123) = 1 + 2 + 3
// so you need a mechanism to extract each digit
crossSum = crossSum + input % 10; // you add the LAST digit to your crosssum
// to make the number smaller (or move all digits one to the right)
// you divide it by 10 at some point the number will be 0 and the iteration
// will stop then.
input = input / 10;
}
cout << crossSum << endl;
system ("pause");
return 0;
}
but still dont understand why theres need of the while statement
Actually, there isn't need (in literal sense) for, number of digits being representable is limited.
Lets consider signed char instead of int: maximum number gets 127 then (8-bit char provided). So you could do:
crossSum = number % 10 + number / 10 % 10 + number / 100;
Same for int, but as that number is larger, you'd need 10 summands (32-bit int provided)... And: You'd always calculate the 10 summands, even for number 1, where actually all nine upper summands are equal to 0 anyway.
The while loop simplifies the matter: As long as there are yet digits left, the number is unequal to 0, so you continue, and as soon as no digits are left (number == 0), you stop iteration:
123 -> 12 -> 1 -> 0 // iteration stops, even if data type is able
^ ^ ^ // to store more digits
Marked digits form the summands for the cross sum.
Be aware that integer division always drops the decimal places, wheras modulo operation delivers the remainder, just as in your very first math lessons in school:
7 / 3 = 2, remainder 1
So % 10 will give you exactly the last (base 10) digit (the least significant one), and / 10 will drop this digit afterwards, to go on with next digit in next iteration.
You even could calculate the cross sum according to different bases (e. g. 16; base 2 would give you the number of 1-bits in binary representation).
Loop is used when we want to repeat some statements until a condition is true.
In your program, the following statements are repeated till the input becomes 0.
Retrieve the last digit of the input. (int digit = input % 10;)
Add the above retrieved digit to crosssum. (crosssum = crosssum + digit;)
Remove the last digit from the input. (input = input / 10;)
The above statements are repeated till the input becomes zero by repeatedly dividing it by 10. And all the digits in input are added to crosssum.
Hence, the variable crosssum is the sum of the digits of the variable input.
Related
This is the question Im trying to solve: Link
Im running this code in an online editor and it gives a memory limit exceeded, even though I have used str+=c instead of str=str+c. And I cant seem to figure out why. Could anyone help me wth this?
#include <bits/stdc++.h>
using namespace std;
void solve(){
int a,b,x;
cin>>a>>b>>x;
string res="";
res+='0';
a--;
while(x--){
cout<<res;
res+=res.back()=='0'?'1':'0';
if(res.back()=='0')
a--;
else
b--;
}
string ans="";
for(char ch: res){
ans+=ch;
if(ch=='0'){
while (a--){
ans+='0';
}
}
else{
while(b--){
ans+='1';
}
}
}
cout<<ans;
}
int main() {
int t;
t=1;
while(t--){
solve();
}
return 0;
}
The input I give is 3 3 3
and output I expect is 101100
Basically your solution idea is nearly correct.
The most important requirement here is the number of tansitions. So, when we go from a 1 to a 0 or from a 0 to a 1. These transitions must exist. And the number of transisitions also determines the minimum numbers of 0es or 1s needed.
If more 0es or 1s should be present, then you can simply repeat any 0 or 1 with the same value. This will have no impact on the transistion.
Let's have a closer look. Below is an example for the minimum number of 0es or 1s for a given number of transitions
Transitions Sequence Min 0es Min 1s
1 01 1 1
2 010 2 1
3 0101 2 2
4 01010 3 2
5 010101 3 3
6 0101010 4 3
You immediately see that there is a simple mathematical relation between the number of transitions and the minimum number of needed 1s or 0es. It is:
(Number of Transitions + 1)/2 rounded up
(Number of Transitions + 1)/2 rounded down
For odd number of transisitions, the minimum numbers of 1s or 0es are always the same. For even numbers of transitions however, it depends on the starting value.
The reverse conclusion is that it does not matter for odd transitions, if you start with a 0 or a 1. For an even number of transitions it is important.
Example:
Input 1 2 2, meaning one 0, two 1s and 2 transitions.
With the above formula, we calculate that we need two digits of the one and 2 digits for the other, so theoretically 010 or 101, But since we shall use only one 0, it can only be 101
Resulting in: If we have an even number of transitions, then the start value may depend from other input parameters. And more precicely: If the minimum number needed for a digit is equal to the given number for that digit, then we must start with the other digit.
Example:
1 2 2 must be 101
2 2 2 can be 0110 or 1001
Knowing that we can now draft an algorithm. We will work only one one of the many solutions.
Check, if the number of transitions is odd or even
If even, then determine the start digit with above condition
create a sequence of 010101... or 10101... depending on the start digit and the given number of sequences
Add the not yet consumed 0es or 1s to the sequence by simply duplicating or repeating existing 0es or ones.
This can then be implemented in a similar way like your approach:
#include <iostream>
#include <string>
int main() {
// Here we will store the input parameters
int numberOfZeroes{}, numberOfOnes{}, numberOfTransitions{};
// The input will always be correct, so need to check it
std::cin >> numberOfZeroes >> numberOfOnes >> numberOfTransitions;
// Start digit
char digit{ '0' };
// Check, if the number of transitions is even, then we need a special additional check
if (numberOfTransitions % 2 == 0) {
// Calculate the minimum number of needed 0es or 1s
const int minimum = (numberOfTransitions + 1) / 2;
// Check, if we need to start with digit 1
if (minimum == numberOfZeroes)
digit = '1';
}
// Now we want to create a string starting made of alternating 0es and 1s, so transitions
std::string sequenceWithTransitions{};
do {
// Build string
sequenceWithTransitions += digit;
// Update counters and digits
if (digit == '1') {
digit = '0'; // Make transition
--numberOfOnes; // Update counter
}
else {
digit = '1'; // Make transition
--numberOfZeroes; // Update counter
}
} while (numberOfTransitions--);
// Fill in the remaining 0es and 1s
std::string result{};
for (char c : sequenceWithTransitions) {
result += c; // Copy value
if (c == '1') // Potential replications of 1
while (numberOfOnes-- > 0)
result += '1';
if (c == '0') // Potential replications of 0
while (numberOfZeroes-- > 0)
result += '0';
}
std::cout << result << '\n';
}
Of course this code can be optimzied in many ways
These are my current errors, I think I did something wrong with the maths but everything I tried didn't work.
Ps: Sorry if my question's formatting is bad, first time using stackflow.
:) credit.c exists
:) credit.c compiles
:) identifies 378282246310005 as AMEX
:) identifies 371449635398431 as AMEX
:) identifies 5555555555554444 as MASTERCARD
:) identifies 5105105105105100 as MASTERCARD
:) identifies 4111111111111111 as VISA
:) identifies 4012888888881881 as VISA
:) identifies 4222222222222 as VISA
:) identifies 1234567890 as INVALID
:) identifies 369421438430814 as INVALID
:) identifies 4062901840 as INVALID
:) identifies 5673598276138003 as INVALID
:( identifies 4111111111111113 as INVALID
expected "INVALID\n", not "VISA\n"
:( identifies 4222222222223 as INVALID
expected "INVALID\n", not "VISA\n"
#include <cs50.h>
#include <math.h>
// Prompt user for credit card number
int main(void)
{
long credit_card, credit_number;
do
{
credit_card = get_long("Enter credit card number: ");
}
while (credit_card < 0);
credit_number = credit_card;
// Calculate total number of digits
int count = (credit_number == 0) ? 1 : (log10(credit_number) + 1);
int summation = 0;
while (credit_number == 0)
{
int x = credit_number % 10; summation += x;
int y = 2 * ((credit_number / 10) % 10);
int r = (y % 10) + floor((y / 10) % 10); summation += r; credit_number /= 100;
}
string card;
// Identify which card type you get after inputing your credit card number
int test = cc / pow(10, count - 2);
if ((count == 13 || count == 16) && test / 10 == 4)
{
card = "VISA";
}
else if (count == 16 && test >= 51 && test <= 55)
{
card = "MASTERCARD";
}
else if (count == 15 && (test == 34 || test == 37))
{
card = "AMEX";
}
else
{
card = "INVALID";
}
// Final verification
if (sum % 10 == 0)
{
printf("%s\n", card);
}
else
{
printf("INVALID\n");
}
}```
Your algorithm is maybe not fully correct. I would therefore propose a different approach. You can look at each single digit in a loop. And, you can also do the whole checksum calculation in one step.
I will show you how to do and explain the algorithm behind it.
BTW. Chosing the right algorithm is always the key for success.
So, first we need to think on how we can extract digits from a number. This can be done in a loop by repeating the follwoing steps:
Perform a modulo 10 division to get a digit
Do a integer division by 10
Repeat
Let us look at the example 1234.
Step 1 will get the 4 -- (1234 % 10 = 4)
Step 2 will convert original number into 123 -- (1234 / 10 = 123)
Step 1 will get the 3 -- (123 % 10 = 3)
Step 2 will convert the previous number into 12 -- (123 / 10 = 12)
Step 1 will get the 2 -- (12 % 10 = 2)
Step 2 will convert the previous number into 1 -- (12 / 10 = 1)
Step 1 will get the 1 -- (1 % 10 = 1)
Step 2 will convert the previous number into 0 -- (1 / 10 = 0)
Then the loop stops. Additionally we can observe that the loop stops, when the resulting divided becomes 0. And, we see addtionally that the number of loop executions is equal to the number of digits in the number. But this is somehow obvious.
OK, then let us look, what we learned so far
while (creditCardNumber > 0) {
unsigned int digit = creditCardNumber % 10;
creditCardNumber /= 10;
++countOfDigits;
}
This will get all digits and count them.
Good. Lets go to next step.
For later validation and comparison purpose we need to get the most significant digit (the first digit) and the second most significant digit (the second digit) of the number.
For this, we define 2 variables which will hold the number. We simply assign the current evaluated digit (and override it in each loop execution) to the "mostSignificantDigit". At the end of the loop, we will have it in our desired variable.
For the "secondMostSignificantDigit" we will simple copy the "old" or "previous" value of the "mostSignificantDigit", before assigning a new value to "mostSignificantDigit". With that, we will always have both values available.
The loop looks now like this:
while (creditCardNumber > 0) {
const unsigned int digit = creditCardNumber % 10;
secondMostSignificantDigit = mostSignificantDigit;
mostSignificantDigit = digit;
creditCardNumber /= 10;
++countOfDigits;
}
OK, now we come to the maybe more complex part. The cheksum. The calculation method is.
Start with the least significant (the last) digit
Do not multiply the digit, which is equivalent with multiplying it with 1, and add it to the checksum
Goto the next digit. Multiply it by 2. If the result is greater than 10, then get again the single digits and add both digits to the checksum
Repeat
So, the secret is, to analyze the somehow cryptic specification, given here. If we start with the last digit, we do not multiply it, the next digit will be multiplied, the next not and so on and so on.
To "not multiply" is the same as multiplying by 1. This means: In the loop we need to multiply alternating with 1 or with 2.
How to get alternating numbers in a loop? The algorithm for that is fairly simple. If you need alternating numbers, lets say, x,y,x,y,x,y,x..., Then, build the sum of x and y and perform the subtratcion "value = sum - value". Example:
We need alternating values 1 and 2. The sum is 3. To get the next value, we subtract the current value from the sum.
initial value = 1
sum = 3
current value = initial value = 1
next value = 3 - 1 = 2. Current value = 2
next value = 3 - 2 = 1. Current value = 1
next value = 3 - 1 = 2. Current value = 2
next value = 3 - 2 = 1. Current value = 1
next value = 3 - 1 = 2. Current value = 2
next value = 3 - 2 = 1. Current value = 1
. . .
Good, now we understand, how to make alternating values.
Next, If we multiply a digit with 2, then the maximum result maybe a 2 digit value. We get the single digits with a modulo and an integer division by 10.
And, now important, it does not matter, if we multiply or not, because, if we do not multiply, then the upper digit will always be 0. And this will not contribute to the sum.
With all that, we can always do a multiplication and always split the result into 2 digits (many of them having the upper digit 0).
The result will be:
checkSum += (digit * multiplier) % 10 + (digit * multiplier) / 10;
multiplier = 3 - multiplier;
An astonishingly simple formula.
Next, if we know C or C++ we also know that a multiplication with 2 can be done very efficiently with a bit shift left. And, additionally, a "no-multiplication" can be done with a bit shift 0. That is extremely efficient and faster than multiplication.
x * 1 is identical with x << 0
x * 2 is identical with x << 1
For the final result we will use this mechanism, alternate the multiplier between 0 and 1 and do shifts.
This will give us a very effective checksum calculation.
At the end of the program, we will use all gathered values and compare them to the specification.
Thsi will lead to:
int main() {
// Get the credit card number. Unfortunately I do not know CS50. I use the C++ standard iostream lib.
// Please replace the following 4 lines with your CS50 equivalent
unsigned long long creditCardNumber;
std::cout << "Enter credit card number: ";
std::cin >> creditCardNumber;
std::cout << "\n\n";
// We need to count the number of digits for validation
unsigned int countOfDigits = 0;
// Here we will calculate the checksum
unsigned int checkSum = 0;
// We need to multiply digits with 1 or with 2
unsigned int multiplier = 0;
// For validation purposes we need the most significant 2 digits
unsigned int mostSignificantDigit = 0;
unsigned int secondMostSignificantDigit = 0;
// Now we get all digits from the credit card number in a loop
while (creditCardNumber > 0) {
// Get the least significant digits (for 1234 it will be 4)
const unsigned int digit = creditCardNumber % 10;
// Now we have one digit more. In the end we will have the number of all digits
++countOfDigits;
// Simply remember the most significant digits
secondMostSignificantDigit = mostSignificantDigit;
mostSignificantDigit = digit;
// Calculate the checksum
checkSum += (digit << multiplier) % 10 + (digit << multiplier) / 10;
// Multiplier for next loop
multiplier = 1 - multiplier;
creditCardNumber /= 10;
}
// Get the least significant digit of the checksum
checkSum %= 10;
// Validate all calculated values and show the result
if ((0 == checkSum) && // Checksum must be correct AND
(15 == countOfDigits) && // Count of digits must be correct AND
((3 == mostSignificantDigit) && // Most significant digits must be correct
((4 == secondMostSignificantDigit) || (7 == secondMostSignificantDigit)))) {
std::cout << "AMEX\n";
}
else if ((0 == checkSum) && // Checksum must be correct AND
(16 == countOfDigits) && // Count of digits must be correct AND
((5 == mostSignificantDigit) && // Most significant digits must be correct
((secondMostSignificantDigit > 0) && (secondMostSignificantDigit < 6)))) {
std::cout << "MASTERCARD\n";
}
else if ((0 == checkSum) && // Checksum must be correct AND
((16 == countOfDigits) || (13 == countOfDigits)) && // Count of digits must be correct AND
((4 == mostSignificantDigit))) { // Most significant digit must be correct
std::cout << "VISA\n";
}
else {
std::cout << "INVALID\n";
}
return 0;
}
What we learn with this example, is integer division and modulo division and the smart usage of the identity element for binary operations.
In case of questions, please ask
Just to be complete, I will show you a C++ solution, based on a std::string and using modern C++ elements and algorithms.
For example, the whole checksum calculation will be done with one statement. The whole program does not contain any loop.
#include <iostream>
#include <string>
#include <regex>
#include <numeric>
int main() {
// ---------------------------------------------------------------------------------------------------
// Get user input
// Inform user, what to do. Enter a credit card number. We are a little tolerant with the input format
std::cout << "\nPlease enter a credit card number:\t";
// Get the number, in any format from the user
std::string creditCardNumber{};
std::getline(std::cin, creditCardNumber);
// Remove the noise, meaning, all non digits from the credit card number
creditCardNumber = std::regex_replace(creditCardNumber, std::regex(R"(\D)"), "");
// ---------------------------------------------------------------------------------------------------
// Calculate checksum
unsigned int checksum = std::accumulate(creditCardNumber.rbegin(), creditCardNumber.rend(), 0U,
[multiplier = 1U](const unsigned int sum, const char digit) mutable -> unsigned int {
multiplier = 1 - multiplier; unsigned int value = digit - '0';
return sum + ((value << multiplier) % 10) + ((value << multiplier) / 10); });
// We are only interested in the lowest digit
checksum %= 10;
// ---------------------------------------------------------------------------------------------------
// Validation and output
if ((0 == checksum) && // Checksum must be correct AND
(15 == creditCardNumber.length()) && // Count of digits must be correct AND
(('3' == creditCardNumber[0]) && // Most significant digits must be correct
(('4' == creditCardNumber[1]) || ('7' == creditCardNumber[1])))) {
std::cout << "AMEX\n";
}
else if ((0 == checksum) && // Checksum must be correct AND
(16 == creditCardNumber.length()) && // Count of digits must be correct AND
(('5' == creditCardNumber[0]) && // Most significant digits must be correct
((creditCardNumber[1] > '0') && (creditCardNumber[1] < '6')))) {
std::cout << "MASTERCARD\n";
}
else if ((0 == checksum) && // Checksum must be correct AND
((16 == creditCardNumber.length()) || (13 == creditCardNumber.length())) && // Count of digits must be correct AND
(('4' == creditCardNumber[0]))) { // Most significant digit must be correct
std::cout << "VISA\n";
}
else {
std::cout << "INVALID\n";
}
return 0;
The lucky numbers are the positive integers whose decimal representations contain only the digits 4 or 7 .enter code here`
For example, numbers 47 , 474 , 4 are lucky and 3 , 13 , 567 are not
if there is no such no then output should -1.
input is sum of digits.
i have written this code:
int main(){
long long int s,no=0,minimum=999999999999999999999;
cin>>s;
for(int i=0; i<=s; i++){
for(int j=0; j<=s; j++){
if(i*4+j*7==s){no=0;
for(int k=0; k<i; k++){
no=no*10+4;
}
for(int l=0; l<j; l++){
no=no*10+7;
}if(no<minimum){
minimum=no;}
}
}
}if(minimum==999999999999999999999){cout<<-1;}
else {cout<<minimum;}
}
it is working fine smaller sum values but input is large then no formed is large due to which i am not able to compare them, the constraints for sum is 1<=n<=10^6
This answer shows a process, one of refinement to develop an efficient solution. The most efficient answer can be found in the paragraphs at the bottom, starting with the text "Of course, you can be even more clever ...".
I've left the entire process in so you can understand the sort of thinking that goes into algorithm development. So, let's begin.
First, I wouldn't, in this case, try to compare large numbers, it's totally unnecessary and limits the sort of ranges you want to handle. Instead, you simply have some number of fours and some number of sevens, which you can easily turn into a sum with:
sum = numFours * 4 + numSevens * 7
In addition, realising that the smallest number is, first and foremost, the one with the least number of digits, you want the absolute minimum number of fours and maximum number of sevens. So start with no fours and as many sevens as needed until you're at or just beyond the required sum.
Then, as long as you're not at the sum, perform the following mutually exclusive steps:
If you're over the desired sum, take away a seven if possible. If there are no sevens to take away, you're done, and there's no solution. Log that fact and exit.
Otherwise (i.e., if you're under the sum), add a four.
At this point, you will have a solution (no solution possible means that you would have already performed an exit in the first bullet point above).
Hence you now have a count of the fours and sevens that sum to the desired number, so the lowest number will be the one with all the fours at the left (for example 447 is less than any of {474, 744}). Output that, and you're done.
By doing it this way, the limitation (say, for example, an unsigned 32-bit int) is no longer the number you use (about four billion, so nine digits), instead it is whatever number of fours you can hold in four billion (about a billion digits).
That's an increase of about 11 billion percent, hopefully enough of an improvement for you, well beyond the 106 maximum sum specified.
In reality, you won't get that many fours since any group of seven fours can always be replaced with four sevens, giving a smaller number (a7777b will always be less than a4444444b, where a is zero or more fours and b is zero or more sevens, same counts in both numbers), so the maximum count of fours will always be six.
Here's some pseudo-code (Python code, actually) to show it in action. I've chosen Python, even though you stated C++, for the following reasons:
This is almost certainly an educational question (there's very little call for this sort of program in the real world). That means you're better off doing the heavy lifting of writing the code yourself, to ensure you understand and also to ensure you don't fail for just copying code off the net.
Python is the most awesome pseudo-code language ever. It can easily read like normal English pseudo-code but has the added benefit that a computer can actually run it for testing and validation purposes :-)
The Python code is:
import sys
# Get desired sum from command line, with default.
try:
desiredSum = int(sys.argv[1])
except:
desiredSum = 22
# Init sevens to get at or beyond sum, fours to zero, and the sum.
(numSevens, numFours) = ((desiredSum + 6) // 7, 0)
thisSum = numSevens * 7 + numFours * 4
# Continue until a solution is found.
while thisSum != desiredSum:
if thisSum > desiredSum:
# Too high, remove a seven. If that's not possible, exit.
if numSevens == 0:
print(f"{desiredSum}: no solution")
sys.exit(0)
numSevens -= 1
thisSum -= 7
else:
# Too low, add a four.
numFours += 1
thisSum += 4
# Only get here if solution found, so print lowest
# possible number that matches four/seven count.
print(f"{desiredSum}: answer is {'4' * numFours}{'7' * numSevens}")
And here's a transcript of it in action for a small sample range:
pax:~> for i in {11..20} ; do ./test47.py ${i} ; done
11: answer is 47
12: answer is 444
13: no solution
14: answer is 77
15: answer is 447
16: answer is 4444
17: no solution
18: answer is 477
19: answer is 4447
20: answer is 44444
And here's the (rough) digit count for a desired sum of four billion, well over half a billion digits:
pax:~> export LC_NUMERIC=en_US.UTF8
pax:~> printf "%'.f\n" $(./test47.py 4000000000 | wc -c)
571,428,597
If you really need a C++ solution, see below. I wouldn't advise using this if this is course-work, instead suggesting you convert the algorithm shown above into your own code (for reasons previously mentioned). This is provided just to show the similar approach in C++:
#include <iostream>
int main(int argc, char *argv[]) {
// Get desired sum from command line, defaulting to 22.
int desiredSum = 22;
if (argc >= 2) desiredSum = atoi(argv[1]);
// Init sevens to get at or beyond desired sum, fours to zero,
// and the sum based on that.
int numSevens = (desiredSum + 6) / 7, numFours = 0;
int thisSum = numSevens * 7 + numFours * 4;
// Continue until a solution is found.
while (thisSum != desiredSum) {
if (thisSum > desiredSum) {
// Too high, remove a seven if possible, exit if not.
if (numSevens == 0) {
std::cout << desiredSum << ": no solution\n";
return 0;
}
--numSevens; thisSum -= 7;
} else {
// Too low, add a four.
++numFours; thisSum += 4;
}
}
// Only get here if solution found, so print lowest
// possible number that matches four / seven count.
std::cout << desiredSum << ": answer is ";
while (numFours-- > 0) std::cout << 4;
while (numSevens-- > 0) std::cout << 7;
std::cout << '\n';
}
Of course, you can be even more clever when you realise that the maximum number of fours will be six, and that you can add one to the sum-of-digits by removing one seven and adding two fours.
So simply:
work out the number of sevens required to get at or just below the desired sum;
add a single four if that will still keep you at or below the desired sum;
then adjust by enough actions of "remove one seven and add two fours" until you get to that desired sum (keeping in mind you may already be there). This will be done exactly once for each unit the shortfall in your current sum (how far it is below the desired sum) so, if the shortfall was two, you would remove two sevens and add four fours (- 14 + 16 = 2). That means you can use a simple mathematical formula rather than a loop.
if that formula results in a negative count of sevens, there was no solution, otherwise use the counts as previously mentioned to form the lowest number (fours followed by sevens).
Just Python for this solution, given how easy it is:
import sys
# Get desired number.
desiredNum = int(sys.argv[1])
# Work out seven and four counts as per description in text.
numSevens = int(desiredNum / 7) # Now within six of desired sum.
shortFall = desiredNum - (numSevens * 7)
numFours = int(shortFall / 4) # Now within three of desired sum.
shortFall = shortFall - numFours * 4
# Do enough '+7-4-4's to reach desired sum (none if already there).
numSevens = numSevens - shortFall
numFours = numFours + shortFall * 2
# Done, output solution, if any.
if numSevens < 0:
print(f"{desiredNum}: No solution")
else:
print(f"{desiredNum}: {'4' * numFours}{'7' * numSevens}")
That way, no loop is required at all. It's all mathematical reasoning.
If I understand the question correctly, you are searching for the smallest number x which contains only the numbers 4 and 7 and the sum of its digits N. The smallest number is for sure written as:
4...47...7
and consists of m times 4 and n times 7. So we know that N = n · 4 + m · 7.
Here are a couple of rules that apply:
(n + m) · 7 ≥ N :: This is evident, just replace all 4's by 7's.
(n + m) · 4 ≤ N :: This is evident, just replace all 7's by 4's.
(n + m) · 7 − N = m · (7 − 4) :: in other words (m+n) · 7 − N needs to be divisible by 7 − 4
So with these two conditions, we can now write the pseudo-code very quickly:
# always assume integer division
j = N/7 # j resembles n+m (total digits)
if (N*7 < N) j++ # ensure rule 1
while ( (j*4 <= N) AND ((j*7 - N)%(7-4) != 0) ) j++ # ensure rule 2 and rule 3
m = (j*7 - N)/(7-4) # integer division
n = j-m
if (m>=0 AND n>=0 AND N==m*4 + n*7) result found
Here is a quick bash-awk implementation:
$ for N in {1..30}; do
awk -v N=$N '
BEGIN{ j=int(N/7) + (N%7>0);
while( j*4<=N && (j*7-N)%3) j++;
m=int((j*7-N)/3); n=j-m;
s="no solution";
if (m>=0 && n>=0 && m*4+n*7==N) {
s=""; for(i=1;i<=j;++i) s=s sprintf("%d",(i<=m?4:7))
}
print N,s
}'
done
1 no solution
2 no solution
3 no solution
4 4
5 no solution
6 no solution
7 7
8 44
9 no solution
10 no solution
11 47
12 444
13 no solution
14 77
15 447
16 4444
17 no solution
18 477
19 4447
20 44444
21 777
22 4477
23 44447
24 444444
25 4777
26 44477
27 444447
28 7777
29 44777
30 444477
The constraints for sum are 1 ≤ n ≤ 106
It means that you might have to find and print numbers with more than 105 digits (106 / 7 ≅ 142,857). You can't store those in a fixed-sized integral type like long long, it's better to directly generate them as std::strings composed by only 4 and 7 characters.
Some mathematical properties may help in finding a suitable algorithm.
We know that n = i * 4 + j * 7.
Of all the possible numbers generated by each combination of i digits four and j digits seven, the minimum is the one with all the fours at left of all the sevens. E.g. 44777 < 47477 < 47747 < ... < 77744.
The minimal lucky number has at max six 4 digits, because, even if the sum of their digits is equal, 4444444 > 7777.
Now, let's introduce s = n / 7 (integer division) and r = n % 7 (the remainder).
If n is divisible by 7 (or when r == 0), the lucky number is composed only by exactly s digits (all 7).
If the remainder is not zero, we need to introduce some 4. Note that
If r == 4, we can just put a single 4 at the left of s sevens
Every time we substitute (if we can) a single 7 with two 4s, the sum of the digits increases by 1.
We can calculate exactly how many 4 digits we need (6 at max) without a loop.
This is enough to write an algorithm.
#include <string>
struct lucky_t
{
long fours, sevens;
};
// Find the minimum lucky number (composed by only 4 and 7 digits)
// that has the sum of digits equal to n.
// Returns it as a string, if exists, otherwise return "-1".
std::string minimum_lucky(long n)
{
auto const digits = [multiples = n / 7L, remainder = n % 7L] {
return remainder > 3
? lucky_t{remainder * 2 - 7, multiples - remainder + 4}
: lucky_t{remainder * 2, multiples - remainder};
} ();
if ( digits.fours < 0 || digits.sevens < 0 )
{
return "-1";
}
else
{
std::string result(digits.fours, '4');
result.append(digits.sevens, '7');
return result;
}
}
Tested here.
The number is huge (cannot fit in the bounds of unsigned long long int in C++). How do we check?
There is a solution given here but it doesn't make much sense.
The solution here tries to repeatedly divide the large number (represented as a string) by 2 but I'm not sure I understand how the result is reached step by step.
Can someone please explain this or propose a better solution?
We cannot use any external libraries.
This is the sample code:
int isPowerOf2(char* str)
{
int len_str = strlen(str);
// sum stores the intermediate dividend while
// dividing.
int num = 0;
// if the input is "1" then return 0
// because 2^k = 1 where k >= 1 and here k = 0
if (len_str == 1 && str[len_str - 1] == '1')
return 0;
// Divide the number until it gets reduced to 1
// if we are successfully able to reduce the number
// to 1 it means input string is power of two if in
// between an odd number appears at the end it means
// string is not divisible by two hence not a power
// of 2.
while (len_str != 1 || str[len_str - 1] != '1') {
// if the last digit is odd then string is not
// divisible by 2 hence not a power of two
// return 0.
if ((str[len_str - 1] - '0') % 2 == 1)
return 0;
// divide the whole string by 2. i is used to
// track index in current number. j is used to
// track index for next iteration.
for (int i = 0, j = 0; i < len_str; i++) {
num = num * 10 + str[i] - '0';
// if num < 2 then we have to take another digit
// to the right of A[i] to make it bigger than
// A[i]. E. g. 214 / 2 --> 107
if (num < 2) {
// if it's not the first index. E.g 214
// then we have to include 0.
if (i != 0)
str[j++] = '0';
// for eg. "124" we will not write 064
// so if it is the first index just ignore
continue;
}
str[j++] = (int)(num / 2) + '0';
num = (num) - (num / 2) * 2;
}
str[j] = '\0';
// After every division by 2 the
// length of string is changed.
len_str = j;
}
// if the string reaches to 1 then the str is
// a power of 2.
return 1;
}
I'm trying to understand the process in the while loop. I know there are comments but they arent really helping me glean through the logic.
Let's start by figuring out how to halve a "string-number". We'll start with 128 as an example. You can halve each digit in turn (starting from the left), keeping in mind that an odd number affects the digit on the right(a). So, for the 1 in 128, you halve that to get zero but, because it was odd, five should be kept in storage to be added to the digit on its right (once halved):
128
v
028
Then halve the 2 as follows (adding back in that stored 5):
028
v
018
v
068
Because that wasn't odd, we don't store a 5 for the next digit so we halve the 8 as follows:
068
v
064
You can also make things easier then by stripping off any leading zeros. From that, you can see that it correctly halves 128 to get 64.
To see if a number is a power of two, you simply keep halving it until you reach exactly 1. But, if at any point you end up with an odd number (something ending with a digit from {1, 3, 5, 7, 9}, provided it's not the single-digit 1), it is not a power of two.
By way of example, the following Python 3 code illustrates the concept:
import re, sys
# Halve a numeric string. The addition of five is done by
# Choosing the digit from a specific set (lower or upper
# digits).
def half(s):
halfS = '' # Construct half value.
charSet = '01234' # Initially lower.
for digit in s: # Digits left to right.
if digit in '13579': # Select upper for next if odd.
nextCharSet = '56789'
else:
nextCharSet = '01234' # Otherwise lower set.
halfS += charSet[int(digit) // 2] # Append half value.
charSet = nextCharSet # And prep for next digit.
while halfS[0] == '0': # Remove leading zeros.
halfS = halfS[1:]
return halfS
# Checks for validity.
if len(sys.argv) != 2:
print('Needs a single argument')
sys.exit(1)
num = sys.argv[1]
if not re.match('[1-9][0-9]*', num):
print('Argument must be all digits')
sys.exit(1)
print(num)
while num != '1':
if num[-1:] in '13579':
print('Reached odd number, therefore cannot be power of two')
sys.exit(0)
num = half(num)
print(num)
print('Reached 1, was therefore power of two')
Running that with various (numeric) arguments will show you the process, such as with:
pax$ python ispower2.py 65534
65534
32767
Reached odd number, therefore cannot be power of two
pax$ python ispower2.py 65536
65536
32768
16384
8192
4096
2048
1024
512
256
128
64
32
16
8
4
2
1
Reached 1, was therefore power of two
(a) Take, for example, the number 34. Half of the 3 is 1.5 so the 1 can be used to affect that specific digit position but the "half" left over can simply be used by bumping up the digit on the right by five after halving it. So the 4 halves to a 2 then has five added to make 7. And half of 34 is indeed 17.
This solution does work only for numbers which are not too large i.e. fits in the range of unsigned long long int.
Simpler C++ solution using bitmanipulation for small numbers :-
int power(string s) {
// convert number to unsigned long long int
// datatype can be changed to long int, int as per the requirement
// we can also use inbuilt function like stol() or stoll() for this
unsigned long long int len = s.length();
unsigned long long int num = s[0]-'0';
for(unsigned long long int i = 1; i<len; i++)
num = (num*10)+(s[i]-'0');
if(num == 1)
return 0;
//The powers of 2 have only one set bit in their Binary representation
//If we subtract 1 from a power of 2 what we get is 1s till the last unset bit and if we apply Bitwise AND operator we should get only zeros
if((num & (num-1)) == 0)
return 1;
return 0;
}
A bit better solution that I could code in Java, which doesn't use any fancy object like BigInteger. This approach is same as simple way of performing division. Only look out for remainder after each division. Also trim out the leading zeroes from the quotient which becomes new dividend for next iteration.
class DivisionResult{
String quotient;
int remainder;
public DivisionResult(String q, int rem){
this.quotient = q;
this.remainder = rem;
}
}
public int power(String A) {
if (A.equals("0") || A.equals("1")) return 0;
while (!A.equals("1")){
DivisionResult dr = divideByTwo(A);
if (dr.remainder == 1) return 0;
A = dr.quotient;
}
return 1;
}
public DivisionResult divideByTwo(String num){
StringBuilder sb = new StringBuilder();
int carry = 0;
for (int i = 0;i < num.length(); i++){
int divisibleNum = carry*10 + (num.charAt(i) - '0');
carry = divisibleNum%2;
sb.append(divisibleNum/2);
}
return new DivisionResult(sb.toString().replaceAll("^0+(?!$)", ""), carry);
}
Let's say that I need to format the output of an array to display a fixed number of elements per line. How do I go about doing that using modulus operation?
Using C++, the code below works for displaying 6 elements per line but I have no idea how and why it works?
for ( count = 0 ; count < size ; count++)
{
cout << somearray[count];
if( count % 6 == 5) cout << endl;
}
What if I want to display 5 elements per line? How do i find the exact expression needed?
in C++ expression a % b returns remainder of division of a by b (if they are positive. For negative numbers sign of result is implementation defined). For example:
5 % 2 = 1
13 % 5 = 3
With this knowledge we can try to understand your code. Condition count % 6 == 5 means that newline will be written when remainder of division count by 6 is five. How often does that happen? Exactly 6 lines apart (excercise : write numbers 1..30 and underline the ones that satisfy this condition), starting at 6-th line (count = 5).
To get desired behaviour from your code, you should change condition to count % 5 == 4, what will give you newline every 5 lines, starting at 5-th line (count = 4).
Basically modulus Operator gives you remainder
simple Example in maths what's left over/remainder of 11 divided by 3? answer is 2
for same thing C++ has modulus operator ('%')
Basic code for explanation
#include <iostream>
using namespace std;
int main()
{
int num = 11;
cout << "remainder is " << (num % 3) << endl;
return 0;
}
Which will display
remainder is 2
It gives you the remainder of a division.
int c=11, d=5;
cout << (c/d) * d + c % d; // gives you the value of c
This JSFiddle project could help you to understand how modulus work:
http://jsfiddle.net/elazar170/7hhnagrj
The modulus function works something like this:
function modulus(x,y){
var m = Math.floor(x / y);
var r = m * y;
return x - r;
}
You can think of the modulus operator as giving you a remainder. count % 6 divides 6 out of count as many times as it can and gives you a remainder from 0 to 5 (These are all the possible remainders because you already divided out 6 as many times as you can). The elements of the array are all printed in the for loop, but every time the remainder is 5 (every 6th element), it outputs a newline character. This gives you 6 elements per line. For 5 elements per line, use
if (count % 5 == 4)