凱薩加密

來自 LIOJ 上的題目,這題實作的東西蠻有趣的,而且這次想到了不同的解法,所以想記錄下來。

解題方向

這一題只要把字串轉成對應的 ASCII CODE,再加上位移量就可以做到位移的動作。唯一要注意的是範圍在 97 ~ 122 之間。

所以這一題的難點在於:當位移後的數字超過 122 時怎麼處理?

解法一 While 迴圈法

這種解法應該是比較直覺的想法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function solve(lines) {
// 位移量
const n = lines[0] * 1
// 原字串
const str = lines[1]
console.log(caesarCipher1(str, n))
}

function caesarCipher1(s, n) {
let result = ''
for(let i=0; i<s.length; i++) {
// 取得 ASCII CODE
const code = s.charCodeAt(i)
// 位移後的數字
let m = code + n
// 取餘數 + 96 直到 <= 122 為止
while(m > 122) {
// 加上 96 是因為 a 從 97 開始
m = (m % 122) + 96
}
// 轉回文字
result += String.fromCharCode(m)
}
return result
}

這裡如果沒有注意的話會不小心把 while(m > 122) 寫成 if(m > 122)

這樣是不對的,因為當 n 的值大於 26 時,(m % 122) + 96 的值就會超過 122,舉個例子:

1
2
3
4
5
6
7
// 假設 n 為 27
let code = 122
let m = code + 27
if(m > 122) {
m = (m % 122) + 96
}
console.log(m) // 123

所以一定要用 while 來處理,才能確保 m 一定落在 97 ~ 122 這個範圍。

解法一 取餘數大法

這一個解法如果想通後會覺得很直覺。

首先,你知道英文字母總共只有 26 個,接著你再想想下面這兩個案例:

  1. 如果往右位移 26 次,是不是就等於沒有動?
  2. 如果往右移 27 次,是不是就等同往右移 1 次?

從這兩個案例中應該能發現一些事情吧?

沒錯,我們只要把「位移量 % 26」,就可以求出實際要位移的次數。

所以其實只要把第一種解法稍微修改一下就好了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function solve(lines) {
// 位移量
const n = lines[0] * 1
// 原字串
const str = lines[1]
console.log(caesarCipher2(str, n))
}

function caesarCipher2(s, n) {
let result = ''
for(let i=0; i<s.length; i++) {
// 取得 ASCII CODE
const code = s.charCodeAt(i)
// code + 實際的位移量
let m = code + (n % 26)
// 如果超出範圍
if(m > 122) {
// 取餘數,並加上 96,因為 a 從 97 開始
m = (m % 122) + 96
}
// 轉回文字
result += String.fromCharCode(m)
}
return result
}

可以注意到 while 變成了 if

這是因為現在的 n 絕對不會超過 26 這個範圍,也就是說 (m % 122) + 96 值絕對不會超過 122,所以這個動作只要做一次就夠了。

雖然不知道這解法對實際效能的影響如何,但能拿掉迴圈看了就是舒服!

圈圈叉叉 平面距離計算
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×