CMU 15-112: Fundamentals of Programming and Computer Science
Week 2: Strings



Code Tracing
What will this code print? Figure it out by hand, then run the code to confirm. Then slightly edit the code and try again.


Free Response (Problem-Solving)

  1. interleave(s1, s2)
    Write the function interleave(s1, s2) that takes two strings, s1 and s2, and interleaves their characters starting with the first character in s1. For example, interleave('pto', 'yhn') would return the string "python". If one string is longer than the other, concatenate the rest of the remaining string onto the end of the new string. For example ('a#', 'cD!f2') would return the string "ac#D!f2". Assume that both s1 and s2 will always be strings.

  2. hasBalancedParentheses(s)
    Write the function hasBalancedParentheses, which takes a string and returns True if that code has balanced parentheses and False otherwise (ignoring all non-parentheses in the string). We say that parentheses are balanced if each right parenthesis closes (matches) an open (unmatched) left parenthesis, and no left parentheses are left unclosed (unmatched) at the end of the text. So, for example, "( ( ( ) ( ) ) ( ) )" is balanced, but "( ) )" is not balanced, and "( ) ) (" is also not balanced. Hint: keep track of how many right parentheses remain unmatched as you iterate over the string.

  3. bestWord
  4. Write the function bestWord(message, letterScores) that takes in a message, a space-separated string of words, and returns the "best" word within the message as defined by letterScores. letterScores is an alphabetical lowercase string where each character occurs at most once, and a character’s index in the string defines the score (starting at 1) of the corresponding character. The score of a word is the sum of all the scores of each character in that word (ignoring case). Return the best word that comes first in alphabetical order in case of ties. For example, if letterScores = "abc", then "a" has 1 point, "b" has 2 points, and "c" has 3 points. Any character not in letterScores should be awarded 0 points. So, using letterScores = "abc", the word "cat" is worth 4 points ("c" has 3 points, "a" has 1 point, and "t" has 0 points). For example,
        bestWord("I love programming", "iaov")
    
    should return "love" because "love" is the highest scoring word, with a score of 0+3+4+0 = 7. And
        bestWord("Programming is FUN", "ufo")
    
    should return "FUN", because although "FUN" and "Programming" both have a highest score of 3, "FUN" is the word that comes first in alphabetical order. . For example,
  5. wordWrap(text, width)
    Write the function wordWrap(text, width) that takes a string of text (containing only lowercase letters or spaces) and a positive integer width, and returns a possibly-multiline string that matches the original string, only with line wrapping at the given width. So wordWrap("abc", 3) just returns "abc", but wordWrap("abc",2) returns a 2-line string, with "ab" on the first line and "c" on the second line. After you complete word wrapping in this way, only then: All spaces at the start and end of each resulting line should be removed, and then all remaining spaces should be converted to dashes ("-"), so they can be easily seen in the resulting string. Here are some test cases for you:
            assert(wordWrap("abcdefghij", 4)  ==  """\
    abcd
    efgh
    ij""")
            assert(wordWrap("a b c de fg",  4)  ==  """\
    a-b
    c-de
    fg""")
    

  6. largestNumber(text)
    largestNumber: Write the function largestNumber(text) that takes a string of text and returns the largest int value that occurs within that text, or None if no such value occurs. You may assume that the only numbers in the text are non-negative integers and that numbers are always composed of consecutive digits (without commas, for example). For example:
        largestNumber("I saw 3 dogs, 17 cats, and 14 cows!")
    
    returns 17 (the int value 17, not the string "17"). And
        largestNumber("One person ate two hot dogs!")
    
    returns None (the value None, not the string "None").

  7. longestSubpalindrome(s)
    Write the function longestSubpalindrome(s), that takes a string s and returns the longest palindrome that occurs as consecutive characters (not just letters, but any characters) in s. So:
       longestSubpalindrome("ab-4-be!!!")
    
    returns "b-4-b". If there is a tie, return the lexicographically larger value -- in Python, a string s1 is lexicographically greater than a string s2 if (s1 > s2). So:
       longestSubpalindrome("abcbce")
    
    returns "cbc", since ("cbc" > "bcb"). Note that unlike the previous functions, this function is case-sensitive (so "A" is not treated the same as "a" here). Also, from the explanation above, we see that longestSubpalindrome("aba") is "aba", and longestSubpalindrome("a") is "a".

  8. sameChars(s1, s2)
    Write the function sameChars(s1, s2) that takes two strings and returns True if the two strings are composed of the same characters (though perhaps in different numbers and in different orders) -- that is, if every character that is in the first string, is in the second, and vice versa -- and False otherwise. This test is case-sensitive, so "ABC" and "abc" do not contain the same characters. The function returns False if either parameter is not a string, but returns True if both strings are empty (why?).

  9. collapseWhitespace(s)
    Without using the s.replace() method, write the function collapseWhitespace(s), that takes a string s and returns an equivalent string except that each occurrence of whitespace in the string is replaced by a single space. So, for example, collapseWhitespace("a\t\t\tb\n\nc") replaces the three tabs with a single space, and the two newlines with another single space , returning "a b c". Here are a few more test cases for you:
        assert(cw("a\nb") == "a b")
        assert(cw("a\n   \t    b") == "a b")
        assert(cw("a\n   \t    b  \n\n  \t\t\t c   ") == "a b c ")
    
    Once again, do not use s.replace() in your solution.

  10. replace(s1, s2, s3)
    Without using the builtin method s.replace(), write its equivalent. Specifically, write the function replace(s1, s2, s3) that returns a string equal to s1.replace(s2, s3), but again without calling s.replace().

  11. encodeOffset(s, d)
    Write the function encodeOffset(s, d) that takes a string and a possibly-negative int offset d (for "delta"), and returns the string formed by replacing each letter in s with the letter d steps away in the alphabet. So: encodeOffset("ACB", 1) return "BDC" encodeOffset("ACB", 2) return "CED" This works with wraparound, so: encodeOffset("XYZ", 1) returns "YZA" And with negative offsets, so: encodeOffset("ABC", -1) returns "ZAB" And the wraparound repeats with d>26, so: encodeOffset("ABC", -27) returns "ZAB" And it is case-preserving, so: encodeOffset("Abc", -27) returns "Zab" And it does not affect non-alphabetic characters (non-letters), so: encodeOffset("A2b#c", -27) returns "Z2a#b"

  12. decodeOffset(s, d)
    Write the function decodeOffset(s, d) that takes a string that was encoded by encodeOffset using the given offset d, and returns the original string.

  13. encrypt and decrypt
    Background: Here we will implement a simple password-based encryption scheme. First, we will start with a plaintext (not encrypted) message, say "Go team!". We will ignore all the non-letters and convert the letters to uppercase, giving us "GOTEAM". That is the message we will encrypt. Next, we need a password, which we assume is all lowercase letters, say "azby". We will think of each letter in the password as a shift, where a is 0 and z is 25, so "azby" specifies the shifts 0, 25, 1, 24 in order. We apply these shifts to the letters of the plaintext message, with wraparound (so after "Z" we go back to "A"). So we will shift "G" by 0 (resulting in "G"), "O" by 25 (resulting in "N"), "T" by 1 (resulting in "U"), and "E" by 24 (resulting in "C"). Then we run out of password characters, so we start over from the beginning of the password. So we shift "A" by 0 (resulting in "A") and "M" by 25 (resulting in "L"). Hence, encrypting "Go team!" with the password "azby" produces the ciphertext (that is, the encrypted text) "GNUCAL".
    • encrypt
    • With the explanation above in mind, write the function encrypt(plaintext, password) that takes two strings, a plaintext message and a password, and which returns the encrypted string that results from the process described above. If the password is not all-lowercase, just return the string "password must be all lowercase". Big Hint: use ord(c) to convert a character to its ASCII/Unicode value. Use chr(v) to go the other way, converting ASCII/Unicode back into a character. So: ord("A") is 65, and chr(65) is "A". And chr(ord("A")+1) is "B".
    • decrypt
    • Now write the other necessary part of any encryption scheme: decryption! Specifically, write the function decrypt(ciphertext, password) that takes two strings, a ciphertext message that was encrypted as described above, and a password. This function returns the original all-caps message that was encrypted. So, for example, decrypt("GNUCAL", "azby") should return "GOTEAM". Hint: decryption is very similar to encryption (which is why it is not worth so many points).