The next problem is another puzzle, but one with an additional instructional purpose. The ability to understand and use technical documentation, whether from a manual or incorporated in a development tool, is an essential skill for all computer professionals. Like many similar skills, practitioners develop it primarily through extended, repeated practice. The "Review" above provides references to examples and documentation to help solve the following problem.
The Cubed Puzzle Problem
cube puzzle problem
Find the smallest integer
whose cube contains the sub-sequence of digits "000"
does not begin or end with a '0' digit
For example, n satisfies the puzzle if n3 = xA000By, where x≠0, y≠0, and A and B are zero or more digits
Puzzle goal.
It's easiest to generate and cube candidate numbers using numeric data, but it's easier to search for specific digits in a string of characters. Following the palindrome-number example, convert from numeric to string data when appropriate.
Problems:
Solve the problem using the C++ string class, especially the find function.
Solve the problem using C-strings. Begin by indexing into the string to examine the first and last character, and use strstr to search for the substring "000." Although a solution using the strchr and strrchr functions to test for leading and trailing 0s is awkward, it's a good problem-solving exercise while reviewing pointer concepts.
Solution outline:
Use a for-loop to generate candidate numbers systematically.
Cubing a number: i3 = i×i×i.
After cubing the candidate, convert the cube to a string.
Cubed puzzle problems and solution outline.
There are many ways to program the solutions. The case-analysis pattern, based on the break and continue operators and illustrated in palindrome programs, is a viable choice. However, for simple cases, it's possible to implement a case analysis using an if-statement by cleverly organizing a chain of logical-AND operations. Recall that:
The overall expression is true only if all sub-expressions are true. See Truth tables.
The logical-AND operators are evaluated left to right.
Short circuit evaluation interrupts the if-statement whenever a sub-expression evaluates to false.
Stop, and try to solve the problems before studying the solutions below.
#include <iostream>
#include <string>
using namespace std;
int main()
{
for (int i = 1; ; i++) // (a)
{
int cube = i * i * i; // (b)
string s = to_string(cube); // (c)
if (s.find('0') != 0 && // (d)
s.rfind('0') != s.length() - 1 && // (e)
s.find("000") != string::npos) // (f)
{
cout << i << " " << cube << endl;
break;
}
}
}
cube.cpp.
Generates the candidate numbers.
Cubes each candidate number.
Converts the cubed number to an instance of the string class.
Although the conversion process doesn't put a leading '0' in the string, the example includes the test to illustrate the find and find_first_of functions. find searches the target string, s, left to right. If it finds a '0' in s, it returns its 0-indexed position; otherwise, it returns string::npos. The puzzle allows a '0' anywhere except the first or zeroth position. The find_first_of can replace find.
rfind operates similarly, but searches in the reverse English reading order: right to left. The puzzle allows a '0' anywhere in s, except at the end. The find_last_of can replace rfind.
find searches the target string, s, left to right for the substring "000" in. If it finds a matching substring, it returns the position of its first character; otherwise, it returns string::npos. This sub-expression is last in the if-statement because searching for a substring is more time-intensive than the previous tests. There are no other string functions that can replace find when the argument is a string.
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
for (int i = 1; ; i++) // (a)
{
int cube = i * i * i; // (b)
char s[100];
_itoa(cube, s, 10); // (c)
if (
s[0] != '0' && // (d)
s[strlen(s) - 1] != '0' && // (e)
strstr(s, "000") != nullptr) // (f)
{
cout << i << " " << cube << endl;
break;
}
}
}
ccube.cpp (1).
The first C-string solution uses indexing, as illustrated in the palindrome example, to test for single characters. The solution is straightforward and efficient.
Generates the candidate numbers.
Cube each candidate number.
Converts the cubed number to a C-string. Recall that _itoa is a non-standard function that is not supported by all C++ compilers (see cpalnumber.cpp) for a simple implementation of this function.
Indexes the target string, s, at the first position, rejecting candidates beginning with a '0' digit.
Indexes the target string, s, at the last position, rejecting candidates ending with a '0' digit.
strstr searches the target, s, from left to right, returning a pointer to the first occurrence of the substring "000" or nullptr if s does not contain the substring. nullptr is the pointer-equivalent of zero, making it possible to simplify the third sub-expression to: strstr(s, "000"). See Alternate representations of Boolean values.
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
for (int i = 1; ; i++)
{
int cube = i * i * i;
char s[100];
_itoa(cube, s, 10);
if (strchr(s, '0') != &s[0] && // (a)
//strchr(s, '0') != s && // (b)
strrchr(s, '0') != &s[strlen(s) - 1] && // (c)
strstr(s, "000") != nullptr) // (d)
{
cout << i << " " << cube << endl;
break;
}
}
}
ccube.cpp (2).
The second C-string solution replaces indexing with the strchr and strrchr functions to test for leading and trailing '0' characters. This solution is "unnatural" and more convoluted than the previous one, but it demonstrates strchr and strrchr.
strchr searches the C-string, s, left to right, returning a pointer to the first occurrence of '0' or nullptr if '0' is not found. The expression &s[0] is a pointer to the first character in string s. The candidate satisfies part of the puzzle's requirement if the first '0' located isn't the first character in the string.
An alternate version of (a). &s[0] ≡ s (recalling that the name of an array or C-string is its address).
strrchr searches C-string, s, in the reverse English reading order, right to left, and returns a pointer to the first occurrence of '0' in the string (equivalent to finding the last '0' in a left-to-right search); it returns nullptr if a '0' is not found. The expression &s[strlen(s) - 1] is a pointer to the last character in the string. Therefore, if the rightmost '0' isn't at the end of the string, the candidate satisfies another puzzle requirement.
See Figure 4(f).
It's also possible to form a solution using strlen in conjunction with the substrings strchr and strrchr return.