8.7.2. cube.cpp and ccube.cpp

Our next problem is another puzzle, but I suggest we take a different approach as we solve it. Learning theorists describe and use many different instructional techniques. However, at their most fundamental level, they all share the goal of helping learners progress efficiently from novices to experts within a specified domain. Knowing how to solve problems within that domain is a significant skill developed through extended practice, separating experts and novices. Two previous examples, cpalnumber.cpp and palnumber.cpp, demonstrate the basic problem solution and some of the needed conversion operations. Another crucial skill is learning how to read and use language-specific documentation, and I'll provide hints and links to help you get started, narrowing your search. Try to solve the problems before studying the solutions below.

The Problem

Find the smallest integer whose cube contains the sub-sequence of digits "000" but does not begin or end with a '0' digit. That is, the cube should be of the form xA000By where x≠0, y≠0, and A and B are zero or more digits except 0. Two program versions illustrate searching for substrings in C-strings and instances of the C++ string class.

The cube and palindrome-number problems have three common steps:

  1. Searching for a small number satisfying a given set of criteria: use a for-loop to generate candidate numbers systematically.
  2. The puzzle specifies a simple arithmetic operation carried out on the candidate numbers, i: i3 = i×i×i.
  3. Convert the result to a string and test it against the problem requirements with string functions.

See the Searching section for a list of C++ string class and C-string searching functions. The top table row labels the string representation for each column. At the top of the page, there are also links to more detailed function descriptions.

Problem 1: solve the problem using the C++ string class and its functions. You can follow the palnumber example, testing the first and last characters by indexing into the string. To expand your experience, I suggest using the find functions (see string Class Functions, especially Figure 4).

Problem 2: solve the problem using C-strings. Although there are C-string functions we can use to examine the first and last characters, using them as needed by the problem is challenging. I recommend following the palnumber example, testing them by indexing the string. Use the C-string strstr function to test for the presence of the "000" substring. Once you have the indexing version working, try replacing the indexing with the strchr and strrchr functions. Please see More C-String Functions, especially Figures 1 and 2, for details and examples of the three C-string functions.

There are many ways to program solutions for these relatively simple problems. We could follow the case-analysis pattern, based on the break and continue operators, illustrated in the palindrome-number programs. Instead, the following programs use an if-statement with a chain of logical-AND operations. The programs organize the sub-expressions in the if-statement to achieve the same benefits as the case analysis. Recall that:

A string Solution

#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_first_of('0') != 0 &&		// (d)
		    s.find_last_of('0') != s.length() - 1 &&	// (e)
		    s.find("000") != string::npos)		// (f)
		{
			cout << i << "   " << cube << endl;
			break;
		}
	}
}
cube.cpp.
  1. Generates the candidate numbers.
  2. Cubes each candidate number.
  3. Converts the cubed number to an instance of the string class.
  4. find_first_of 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 problem allows a '0' anywhere except the first or zeroth position. This function is relatively lightweight, completing quickly.
  5. find_last_of operates similarly but searches right to left. The test accepts a '0' anywhere in s except in the last position. This function also completes quickly.
  6. find searches the target string, s, left to right. If it finds the substring "000" in s, it returns the 0-indexed position of the sub-string's first character; otherwise, it returns string::npos. Searching for a sub-string requires more processing time and effort than searching for a single character (see the Knuth-Morris-Pratt algorithm).

Two C-String Solutions

#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 to test for single characters. This version is the most simple and likely the most efficient.
  1. Generates the candidate numbers.
  2. Cubes each candidate number.
  3. 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.
  4. Indexes the target string, s, at the first position, rejecting candidates beginning with a '0' digit.
  5. Indexes the target string, s, at the last position, rejecting candidates ending with a '0' digit.
  6. 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.
#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)
		{
			cout << i << "   " << cube << endl;
			break;
		}
	}
}
ccube.cpp (2). The second C-string solution replaces indexing to test for leading and trailing '0' characters with the strchr and strrchr functions.
  1. strchr searches 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.
  2. An alternate version of (a). &s[0] ≡ s (recalling that the name of an array or C-string is its address).
  3. The expression &s[strlen(s) - 1] is a pointer to the last character in C-string s.