# 程式導師 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 狀況。