HackerRank python练习——Caesar Cipher

Caesar Cipher

题目链接

caesarCipher函数代码如下:

def caesarCipher(s, k):
    result = ''
    for i in s:
        if 65 <= ord(i) <= 90:
            dif = k - (ord('Z') - ord(i))
            if dif % 26 != 0:
                result += chr(ord('A') + dif % 26 - 1)
            else:
                result += 'Z'

        elif 97 <= ord(i) <= 122:
            dif = k - (ord('z') - ord(i))
            if dif % 26 != 0:
                result += chr(ord('a') + dif % 26 - 1)                
            else:
                result += 'z'
        else:
            result += i
    return result

另一种写法:

    result = ''
    letters = [chr(i) for i in range(97,123)]    # 小写
    Letters = [chr(i) for i in range(65,91)]    # 大写
    for i in s:
        if i in letters:
            leftnum = ord('z') - ord(i)
            left_k = k - leftnum
            if left_k >= 0:
                if left_k % 26 == 0:
                    result += 'z'
                else:
                    result += letters[left_k % 26 - 1]
            else:
                result += letters[letters.index(i) + k]
        elif i in Letters:
            leftnum = ord('Z') - ord(i)
            left_k = k - leftnum
            if left_k >= 0:
                if left_k % 26 == 0:
                    result += 'Z'
                else:
                    result += Letters[left_k % 26 - 1]
            else:
                result += Letters[Letters.index(i) + k]
        else:
            result += i
    return result

遍历字符串s,获得的变量i有2种情况:一种是字母,一种是非字母。
当是非字母时,直接输出即可。
当是字母时,则有大小写区分。不论大小写,最后求偏移k后所得字母的方法是一样的。以小写为例。
变量i在a到z这一个区间中,将a到z作为一个列表,问题则变为指针从变量i开始移动,经过移动k次后指针停在哪个字母上。主要要解决的是指针移动到z后回到开头从a开始继续移动。那么k就有两种情况,一种是从变量i开始移动k次后仍未移动完列表(即没有到z),此时,直接用变量i的索引值加k即可求得最后的字母的索引值;另一种情况是k要大于变量i到z的差,那么就需要知道从变量i到z后,k还剩下多少,用new_k表示。再从a开始循环遍历列表,用new_k对26取余(取整是求完整遍历列表的次数,取余是求完整遍历列表后剩下的步数)。因为a在列表里的索引值是0,所以最后求字母的索引值时需要将取余后的值即new_k%26减去1.
用chr()和ord()函数转换时需要注意,相当于大小写的a的索引值不是0,所以要加上大小写a的索引值。
看了下Discussions里其他人的代码,发现有更简单的思路,代码如下:

def caesarCipher(s, k):
    for i in range(len(s)):
        '''
        a-z的ASCII值:97-122
        A-Z的ASCII值:65-90
        '''
        if ord(s[i]) in range(97,123):
            s = s[:i] + chr((ord(s[i]) - 97 + k) % 26 + 97) + s[i+1:]
        elif ord(s[i]) in range(65,91):
            s = s[:i] + chr((ord(s[i]) - 65 + k) % 26 + 65) + s[i+1:]
    return s

此代码的亮点:1.用到了字符串的切片。2.仍以小写为例:chr((ord(s[i]) - 97 + k) % 26。亮点是计算a到s[i]的步数,它相当于是从a开始移动ord(s[i])-97次,后又移动k次后所指向什么字母。那么,我们就只需要将它们之和对26取余,即可获得最后剩下的步数。因为是从a开始的,而a的索引值不是0而是其ASCII值,故最终需要加上大小写a的ASCII值。
此方法比我的更简单,不用考虑从字母变量i开始移动k步后是否到字母z。少了好几步。

你可能感兴趣的:(HackerRank练习)