# 程式導師 Week2 作業檢討 ###### tags: `程式導師` `JavaScript` `題目` ## hw1:印出星星 給定 n(1<=n<=30),依照規律「印出」正確圖形 ```javascript= function printStars(n) { var stars = ""; for(var i=0; i<n; i++){ stars = stars + "*"; } console.log(stars); } ``` ``` printStars(1) 正確輸出: * ``` ``` printStars(3) 正確輸出: * * * ``` ``` printStars(6) 正確輸出: * * * * * * ``` ## hw2:首字母大寫 給定一字串,把第一個字轉成大寫之後「回傳」,若第一個字不是英文字母則忽略。 ``` capitalize('nick') 正確回傳值:Nick capitalize('Nick') 正確回傳值:Nick capitalize(',hello') 正確回傳值:,hello ``` > :bulb: **想法** > > 原本的寫法是: > 1. 先設定一個空字串 > 2. 用 Ascii Code 判斷第一個字是否為英文小寫 > 3. 是的話,就轉成英文大寫,放到空字串內 > 4. 接著再從原字串的第二個字開始遍歷,依序將字塞入空字串內 > > 但這個寫法會導致第四步驟,將原字串的第二個字依序放入新字串內後,新字串就會變成 NaN。(如下方所示) > ```javascript= function capitalize(str) { var newString = ""; if (str.charCodeAt(0)>=97 && str.charCodeAt(0)<=122) { newString += String.fromCharCode(str.charCodeAt(0)); //這裡的 newString 確定成功轉為大寫英文字母 for (var i=1; i<str.length; i++){ //這裡開始後的 newString 就變成 NaN newString =+ str[i]; } return(newString); } else { return(str); } }; ``` > 所以解題想法改成先分類、再轉換: > 1. 先設定一個空字串 > 2. 如果 Ascii code 判斷的第一個字是英文字,才進入判斷大小寫。 > 3. 如果 Ascii code 判斷的第一個字不是英文字,就直接輸出原字串。 > 4/ 如果是大寫,就直接輸出原字串。 > 5. 如果是小寫,就轉成大寫,再用 .slice(1)將字串第二個之後的字切出來,跟大寫字拼在一起。 > ```javascript= function capitalize(str) { var newString = ""; if (str.charCodeAt(0)>=65 && str.charCodeAt(0)<=122) { if(str.charCodeAt(0)>=97 && str.charCodeAt(0)<=122) { var exchanged = String.fromCharCode(str.charCodeAt(0)); var following = str.slice(1); newString = exchanged + following; return(newString); } else { return(str); } } else { return(str); } }; console.log(capitalize('nick')); console.log(capitalize('Nick')); console.log(capitalize(',hello')); ``` ## hw3:反轉字串 給定一個字串,請「印出」反轉之後的樣子(不能使用內建的 reverse 函式) ``` reverse('yoyoyo') 正確輸出:oyoyoy reverse('1abc2') 正確輸出:2cba1 reverse('1,2,3,2,1') 正確輸出:1,2,3,2,1 ``` > :bulb: **想法** > > 採用與陣列相同的遍歷方式,遍歷字串。但這次需要反向遍歷字串,所以從原本正向的 i++ 改成 i--,且初始值是字串長度減一,才會剛好抓到最後一項。 > > 原本不想先設定一個空字串,改在圈內執行 `str += str[i]`,才發現不對,因為 str 會隨著再迴圈執行而變動,越後面的 str 會變得超長。 > ```javascript= function reverse(str) { var newString = ""; for (var i=str.length - 1; i>=0; i--) { newString += str[i]; } console.log(newString); } reverse('yoyoyo'); reverse('1abc2'); reverse('1,2,3,2,1'); ``` ## hw4:印出因數 先幫大家複習一下數學,給定一個數字 n,因數就是所有小於等於 n 又可以被 n 整除的數,所以最明顯的例子就是 1 跟 n,這兩個數一定是 n 的因數。現在請寫出一個函式來「印出」所有的因數 ``` printFactor(10) 正確輸出: 1 2 5 10 printFactor(7) 正確輸出: 1 7 ``` ```javascript= function printFactor(n) { for (var i=1; i<=n; i++) { if (n%i===0) { console.log(i); } } } printFactor(10); printFactor(7); ``` ## hw5:自己的函式自己寫 其實仔細思考的話,你會發現那些陣列內建的函式你其實都寫得出來,因此這一題就是要讓你自己動手實作那些函式! 我們要實作的函式有兩個:join 以及 repeat。(再次強調,這一題要你自己實作這些函式,所以你不會用到內建的join以及repeat) join 會接收兩個參數:一個陣列跟一個字串,會在陣列的每個元素中間插入一個字串,最後回傳合起來的字串。 repeat 的話就是回傳重複 n 次之後的字串。 ```javascript= function join(arr, concatStr) { var str = ""; for (var i=0; i<arr.length; i++) { str = str + arr[i] + concatStr; } return(str); } function repeat(str, times) { var newStr = ""; for (var i=1; i<=times; i++) { newStr += str; } return(newStr); } console.log(join(['a'], '!')); console.log(join([1, 2, 3], '')) console.log(join(["a", "b", "c"], "!")) console.log(join(["a", 1, "b", 2, "c", 3], ',')) console.log(repeat('a', 5)); console.log(repeat('yoyo', 2)); ``` ## 挑戰題 > :bulb: 想法 > > 原本只想到用 for 迴圈,但用 for 迴圈的話,就必須確定`i++`或`i--`,然而這題的`i++`或`i--`,會隨著每次步驟而改變。 > 所以這題要用 `while` 條件是設定結束條件,結束條件就是當最小的搜尋位置等同最大搜尋位置,就結束迴圈。 > ```javascript= const search=(arr, n) => { var maxIndex = arr.length - 1 var minIndex = 0 while(minIndex <= maxIndex) { var centerIndex = Math.floor((maxIndex - minIndex) /2 + minIndex); if (n === arr[centerIndex]) { return(centerIndex); } else if (n > arr[centerIndex]) { minIndex += 1; } else { maxIndex -= 1; } } return(-1) }; console.log(search([1, 3, 10, 14, 39], 14)) //3 console.log(search([1, 3, 10, 14, 39], 299)) //-1 ``` 第六行計算中間值的方式,不用 `(minIndex+maxIndex)/2` 而用 `(maxIndex-minIndex)/2 + minIndex` 是為了避免當數值很大時,可能產生的 overflow 狀況。