You have already written one function per problem. This lesson is about writing more of them: small helpers that each do one thing, and the rules for what happens to the values you pass in.
A helper function#
Checking whether a character is a vowel is a small, separate job. Give it a name:
bool isVowel(char c) {
c = tolower(c);
return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
}
int countVowels(char* s) {
int count = 0;
for (int i = 0; s[i] != '\0'; i++) {
if (isVowel(s[i])) count++;
}
return count;
}
class Solution {
bool isVowel(char c) {
c = tolower(c);
return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
}
public:
int countVowels(string s) {
int count = 0;
for (char c : s) {
if (isVowel(c)) count++;
}
return count;
}
};
class Solution {
private boolean isVowel(char c) {
c = Character.toLowerCase(c);
return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
}
public int countVowels(String s) {
int count = 0;
for (char c : s.toCharArray()) {
if (isVowel(c)) count++;
}
return count;
}
}
def is_vowel(c):
return c.lower() in "aeiou"
def countVowels(s):
return sum(1 for c in s if is_vowel(c))
In C and Python, write the helper above the function the judge calls. In C++ and Java, put it inside class Solution next to it.
A helper earns its place when it has a clear name and hides a detail. The main function then reads as a description of the solution rather than a pile of steps.
What happens to the arguments#
This is the part that trips people up, because the four languages behave differently, and a bug here looks like the computer ignoring you.
Numbers are always copied. Change one inside a function and the caller's copy is untouched, in every language.
Arrays and lists are not copied in Java, Python and C. The function receives a way to reach the same array, so changing an element inside the function changes it for the caller too.
void zeroFirst(int* nums) {
nums[0] = 0; // the caller's array changes
}
void byValue(vector<int> nums) {
nums[0] = 0; // changes a copy; the caller sees nothing
}
void byReference(vector<int>& nums) {
nums[0] = 0; // the & means the caller's vector changes
}
void zeroFirst(int[] nums) {
nums[0] = 0; // the caller's array changes
}
def zero_first(nums):
nums[0] = 0 # the caller's list changes
C++ is the odd one out: a vector passed normally is copied, all of it. Add & to pass the original instead. That matters for speed as well as correctness. A helper called n times that copies an n element vector each time is quietly quadratic. When a helper only reads a vector, pass it as const vector<int>& nums.
Returning more than one thing#
Sometimes a helper needs to give back two values, such as a minimum and a maximum.
// C has no pairs, so write results through pointers.
void minMax(int* nums, int n, int* lo, int* hi) {
*lo = nums[0];
*hi = nums[0];
for (int i = 1; i < n; i++) {
if (nums[i] < *lo) *lo = nums[i];
if (nums[i] > *hi) *hi = nums[i];
}
}
// Called as: int lo, hi; minMax(nums, n, &lo, &hi);
pair<int, int> minMax(const vector<int>& nums) {
return {*min_element(nums.begin(), nums.end()),
*max_element(nums.begin(), nums.end())};
}
// Called as: auto [lo, hi] = minMax(nums);
// Return a small array, or define a record for anything clearer.
int[] minMax(int[] nums) {
int lo = nums[0], hi = nums[0];
for (int x : nums) {
lo = Math.min(lo, x);
hi = Math.max(hi, x);
}
return new int[] {lo, hi};
}
def min_max(nums):
return min(nums), max(nums)
# Called as: lo, hi = min_max(nums)
A function that calls itself#
A function may call itself, as long as each call is on a smaller piece of the problem and there is a case small enough to answer directly. That is recursion, and it is how most tree problems are solved. It gets a lesson of its own later on; for now, notice that nothing new is needed to write one. It is an ordinary function that happens to call its own name.
Try it#
Valid palindrome is a good place to use a helper: one that decides whether a character counts (a letter or a digit) and one that compares two characters ignoring case. The main function is then a short loop that reads like the problem statement.