Week3 解題思考、想法、心得
前言
因為這周有測試系統,而我自己其實也覺得很多東西要學廣一點,所以是額外開個資料夾把這周的預設檔案放進去,然後開始寫,可能也會試著寫測試等通過測試之後再把正確的給提交吧!
hw1:好多星星
給定 n(1<=n<=30),依照規律「回傳」正確圖形(每一行是一個陣列的元素)
n = 1
["*"]n = 3
["*", "**", "***"]n = 6
["*", "**", "***", "****", "*****", "******"]
對於這題的想法,很明顯就是需要回傳一個陣列,所以會需要一個迴圈,然後依序 .push 添加結果。最後回傳 arr。
function stars(n) {
let arr = [];
for (let i = 1; i <= n; i += 1) {
arr.push('*'.repeat(i))
}
return arr
}
hw2:大小寫互換
給定一字串,把小寫字母轉成大寫,大寫字母轉成小寫之後回傳,若不是英文字母則忽略。
input: nick
output: NICKinput: Nick
output: nICKinput: ,hEllO122
output: ,HeLLo123
一個個判斷大小寫之後改寫添加進新變數,然後回傳變數。
function alphaSwap(str) {
let result = '';
for(let i = 0; i < str.length; i += 1) {
if (str[i] > 'A' && str[i] < 'Z') {
result += str[i].toLowerCase();
} else {
result += str[i].toUpperCase();
}
}
return result;
}
hw3:判斷質數
給定一個數字 n(1<=n<=100000),請回傳 n 是否為質數(質數的定義:除了 1 以外,所有小於他的數都無法整除)
n = 2 => true
n = 3 => true
n = 10 => false
n = 37 => true
n = 38 => false
就是判斷質數,之前寫過了,但是這邊因為在練習先寫測試再寫 code 所以花了一些時間再找更大的質數,好方便測試。
function isPrime(n) {
if (n === 1) return false;
for (let i = 2; i <= Math.sqrt(n); i += 1) {
if (n % i === 0) {
return false;
}
}
return true;
}
hw4:判斷迴文
給定一個長度小於 100 的字串 s,請回傳 s 是否為迴文(迴文的定義:正著唸倒著念都一樣)
abcba => true
apple => false
aaaaa => true
applppa => true
最開始的想法是一個個比較,但突然想到如果字串長度是奇數的話,好像有點難比較,後來想想有奇數的話中間就不用判斷了,後來想法是寫一個 function 回傳反過來的字串,之後再把這個 function 回傳的值與字串作比較,如果一樣的話就回傳 true。
本來想試試看能不能直接把字串反傳於是直接使用 reverse 但發現不行,查過之後原來他只能反轉陣列,所以就把字串切開再反轉再結合就可以反轉了。
後來想到題目沒定義大小寫問題,但是因為定義那邊說用念的,所以一般人在念的時候並不會特別強調是大小寫,所以就再加個轉小寫之後再來判斷。
function isPalindromes(str) {
str = str.toLowerCase();
let newStr = str.split('').reverse().join('');
if (newStr !== str) {
return false;
} else {
return true;
}
}
hw5:大數加法
給定兩個長度為 l(1<=l<=1000)的數字(但型態為字串),請回傳兩個數字相加後的結果。
提示:
- 這題不是要考你型態轉換,而且這題很難,真的很難
- 小時候怎麼做直式加法,這一題就怎麼做,可以拿紙跟筆試試看
"123"+"456" => "579"
"12312383813881381381"+"129018313819319831" => "12441402127700701212"
預先想了一下大數加法的做法,目前想到兩個方向,一是拆成陣列之後各自相加,最後再用 .join 串在一起之後回傳。第二種是位元運算的方法,初步猜想是把每個位元給相加之後轉換 10 進位再回傳。
因為傳入的是字串所以要先把字串轉成數字,而且直式加法是由最後一位開始往前加數字的,從後面往前數最後一個陣列是個位數,次後一個是十位數,依此類推,所以可能要另外開一個 function 來單一計算之後再回傳乘 10
本來有顧慮到加法長度不同的問題,但是看題目都沒寫,而且也想到要作長度不同的話,轉換上也有難度,因為還必須要把較短的一方填上 0 才可以相加,不過這一點可以先忽略,假定題目都是給同樣的位數。這樣會比較容易思考。
測試之後發現,大數直接儲存之後呼叫都沒辦法印出正確值,所以超過一定的範圍就必須要轉成字串,不然會無法正確儲存,即使把大數後來再轉成字串也一定不會回傳正確的值,所以就必須要避免數字太大。
轉數字,arrA[0] = parseInt(arrA[0]),如果原來是數字經過處理也還是數字
所以我是不是應該:
- 寫一個 function 把字串轉成陣列,再轉型態為數字。
- 寫一個 function 把較短的一方補上 0。可能的話要把陣列反轉以方便添加0。
- 寫一個 function 把對應的陣列相加。
- 寫一個每提升一位就*10 的 function。
- 寫個判斷大於 9 就處理進位的 function
先把字串反轉,然後從 index 0 開始帶入 function 1,然後送到 function 3 相加,返回後根據 index 0 開始每 +1 就 *10 之後回傳
目標是想一位一位相加,要處理的點是進位,進位要用判斷式來判斷,如果大於 9 就利用 function 5
後來發現可以利用先完成的字串擺後面,新計算出來的擺前面,直接作字串相加,就可以少去位數的處理步驟。
var a1 = '5' // 第一個運算完成
var a2 = '4' // 第二個運算完成
var a = a2 + a1
console.log(a)
//45
修正
- 寫一個 function 把字串轉成陣列。
- 寫一個 function 把陣列反轉後,把較短的一方補上 0,直到兩邊的長度等於最長的一邊+1。
- 寫一個 function 把對應的陣列轉型態為數字,再相加,再轉成字串回傳。
- 寫個 function 判斷有沒有大於 9,有的話進位處理。這好像不適合寫成function。
- 從 index 0 開始把 index n 放後面與 index n+1 相加,達成位數的累積。
判斷大小的時候字串可以跟數字相比。
a = ‘10’
if (a > 9) {
console.log(‘yes’)
}
// yes
目前處理的:
- 直接把字串拆開之後反轉,並賦值新陣列變數名稱。
- 判斷誰比較長,取得較長的為變數 length。
- 寫一個 function 添加 0,次數可以用 length - 該陣列的長度來計算,把這個 function 加入步驟 2 的判斷式裡面。
- 開始寫迴圈,判斷只要全部的數字相加之後小於 10,直接相加,大於10 則進位處理。
思考如何處理進位?
額外做一個進位的變數,只要判斷有進位,就把這個變數賦值 1,然後再與 function 3 相加,後面思考進位處理還是需要另外的 function 會比較好。
利用一個進位變數只要有進位就改值為 1,然後下次的輪迴就可以添加 1。進位處理要另外寫過,判斷該進位時候,就在下一輪進位,進位完之後進位值歸零。
迴圈中一開始就要先把 index 0 相加,然後再判斷是不是需要進位,需要則把進位變數 = 1,然後下一輪的時候才可以相加,下一輪,相加後,再判斷需不需要進位,需要把進位變成 = 1
卡了半天的進位處理,結果居然從 debugger 抓出來,真是感謝 chrome 的神工具。原來我再判斷的時候忘記把進位變數一起放進去判斷了,導致我判斷出來的結果一直有問題,所以才會再相加的時候一直出問題。後來修正完成之後,結果 all right。然後我就感到很錯愕,居然在這種小地方卡了兩個小時,不過大致上我還是覺得很爽,因為終於解出答案來了!
function add(a, b) {
let arrA = a.split('').reverse(); // 切成陣列且反轉
let arrB = b.split('').reverse();
let length = 0;
if (a.length >= b.length) { // 找出誰比較長,用較長者作迴圈次數計算
length = a.length;
zeroPadding(arrB, (length - b.length)); // 把另外一邊補零
} else {
length = b.length;
zeroPadding(arrA, (length - a.length));
} // 得到最長的字串長度,以及兩數修為一樣長的陣列
let result = ''; // 回傳結果的變數
let carryNum = '0'; // 進位用的變數
for (i = 0; i < length; i += 1) { // 計算值
if (littleAdd(arrA[i], arrB[i], carryNum) < 10) { // 判斷有無進位
result = littleAdd(arrA[i], arrB[i], carryNum) + result;
carryNum = '0' // 無進位改為 0
} else { // 進位處理
result = carryProcessing(littleAdd(arrA[i], arrB[i], carryNum)) + result;
carryNum = '1'; //這要下一輪才能使用
}
if (i === length - 1 && carryNum === '1') { // 只判斷最後一位數需不需要進位
result = carryNum + result;
}
}
return result;
}function zeroPadding(arr, n) {
for (let i = 1; i <= n; i += 1) {
arr.push('0')
}
return arr
}function littleAdd(a, b, c = '0') { // c 是進位
a = parseInt(a); // 轉換成數字
b = parseInt(b);
c = parseInt(c);
return a + b + c + '';//相加後回傳字串
}function carryProcessing(str) {
return str[1];
}module.exports = add;
收穫:在這些題目之中,大多數其實都已經做過了,所以還滿快就得到解答了,大致就是之前解過的小變化題而已。當然 hw5 就不一樣了,算是完全沒解過的題目,也的確滿難的,從一開始以為就應該沒太困難,所以覺得還好的態度,然後一跳進來研究之後,越研究才發現的確是很多地方需要克服,就也認知到這的確是個有難度的題目,所幸在提示之下跟我的努力解析,最終還是作出像樣的回答了,感覺十分良好。