Python Fundamentals Practice Problems - Challenge 2 (Palindrome)

Hey,

I am currently struggling with this challenge:

https://app.dataquest.io/m/1012/python-fundamentals-practice-problems/3/palindrome

Unfortunately, even the provided answer doesn’t completely help me. I understand that you start by comparing the first and the last letter and loop letter by letter through the whole word to see if they are similar or not. However, the translation into code dosn’t work for me. Hence, I would be very thankful if somebody could walk me verbally through the provided solution:

def is_palindrome(dna):
n = len(dna)
for i in range(n // 2):
if dna[i] != dna[n - i - 1]:
return False
return True

Thank you very much
Daniel

Hi Daniel. I think there are 2 ideas that will be helpful to keep in mind as you examine the function. The first idea is that we can treat a string like a list, where each character is an element of the list. The 2nd idea is that the range() function generates a list of integers, up to but not including the last number. For example, range(3) would generate the list [0, 1, 2].

In the palindrome() function, we take in the string and determine its length so that we know how many comparisons we have to do (half the length of the string). Since we don’t have to compare the middle value of a string with an odd number of characters, the // operator works well.

In the first input example 'TAAT', the string length is 4, so our loop will be for i in [0, 1], since range(n // 2) works out to range(2). Because we can treat the string as a list, we will have the following values:

dna[0] = 'T'
dna[1] = 'A'
dna[2] = 'A'
dna[3] = 'T'

Hopefully writing it out that way makes it clearer why we used dna[i] and dna[n - i - 1] for our comparisons. The first iteration will have you comparing dna[0] and dna[3], and the 2nd iteration compares dna[1] and dna[2].

If at any point the 2 values are not equal, the if-statement is processed and we return False. Otherwise, the loop will run its course and automatically return True.

I hope that helps!

1 Like

Hi april.g:

You said that

the range() function generates a list of integers, up to but not including the last number. For example, range(3) would generate the list [0, 1, 2]

But when I put in range(3), the result is [0, 3]. What went wrong? I am so confused now. Thanks in advance!

Hi @summeranan. Could you copy your code so I can better understand what you mean in context? Using range(3) with a loop as shown above doesn’t print out the list (you can use print(list(range(3))) to get Python to print out the list), so I’m not sure what case would cause you to get a [0, 3] result.

Hi @april.g, thanks for the reply! So when asking the question, I was just encountering the range() function for the first time and wasn’t sure what it does. Trying to figure it out, I wrote print(range(3)) and the result was range(0, 3), hence the confusion.

I now realized that to have the expected result [0, 1, 2], I’d have to use list(range(3)), or to put it in a for loop like in this exercise.

I guess this is the first time I came across a function that’s not mentioned in the main curriculum so it took a while to figure it out. Is studying on our own for practice problems a common thing as we progress? It won’t be a problem but I just wanna be mentally prepared. Thanks again!

I’m glad you got it worked out! I had a feeling that might have been the case but I wasn’t sure. :slight_smile:

I don’t know that range() is really explained in the curriculum, though it probably should be introduced because it comes up periodically (like in this practice exercise). I think for the most part the DQ curriculum is self-contained, but you may find yourself exploring other sources anyway as part of the learning process. Because of that I’ve gotten better at searching and reading documentation.

And you can always ask the community if something is unclear! Happy coding!

Hi @april.g Same here. I was not familiar with the range function. So, I ended up spending a lot of time on this practice exercise (because I liked the challenge!). Most time was spent on figuring how to iterate over any length string. It gives correct output but the solution code I came up with is rather inelegant I think . Can you please critique the code? Appreciate your time. Thank you!

‘’’
def is_palindrome(dna):
num_chars = len(dna)

if num_chars == 1:
    return True

if num_chars == 2 or num_chars == 3:
    char_list = []
    for char in dna:
        char_list.append(char)
    if char_list[0] == char_list[(num_chars-1)]:
        return True
    else:
        return False # 1st & last chars don't match; can stop here & return False

if num_chars%2 != 0:  # for ODD string length > 3 chars
    char_list = []
    for char in dna:
        char_list.append(char)
    check_upto = (num_chars -1) / 2
    start_index = 0
    for char in char_list:
        if char_list[start_index] == char_list[(num_chars-1-start_index)]: #match
            start_index +=1
            if start_index == check_upto:
                return True
        else:
            return False # 1st & last don't match; can stop here & return False
            
else: # # for EVEN string length > 2 chars
    char_list = []
    for char in dna:
        char_list.append(char)
    check_upto = num_chars / 2
    start_index = 0    
    for char in char_list:
        if char_list[start_index] == char_list[(num_chars-1-start_index)]:
            start_index +=1
            if start_index == check_upto:
                return True
        else:
            return False # 1st & last don't match; can stop here & return False

‘’’

Congrats on taking on the challenge and blazing your own trail! There’s so many ways to approach these types of problems and I think it’s great that you were able to apply what you knew for this challenge.

I’m not really informed about optimizing code, but I can share these two things with you that I think will be beneficial.

One thing you’ll be happy to learn is that we can treat a string just like a list. This means if I have input_1 = 'TAAT', then I can say:

input_1[0] = 'T'
input_1[1] = 'A'
input_1[2] = 'A'
input_1[3] = 'T'

This means we don’t have to create a character list from the string, we can just reference each character as if it’s already a list. See how this will change this portion:

if num_chars%2 != 0:  # for ODD string length > 3 chars
    check_upto = (num_chars -1) / 2
    start_index = 0
    for char in dna:
        if dna[start_index] == dna[(num_chars-1-start_index)]: #match
            start_index +=1
            if start_index == check_upto:
                return True
        else:
            return False # 1st & last chars don't match; can stop here & return False

The 2nd thing is that you will be happy about is that the code still works when we eliminate the scenario where num_chars is 2 or 3. I deleted it and the code still passed.

You may want to revisit the problem later and see how you would approach it differently, or to optimize your code even more!

Happy coding!

1 Like

Many thanks for the feedback points that helped clean up :relieved: