1. 程式人生 > 其它 >九日集訓 Day 2 迴圈

九日集訓 Day 2 迴圈

一、概念定義

對於迴圈來說,C/C++ 語言中總共有兩種結構,while 和 for,但是對於刷題來說,其實兩者沒有本質區別,所以這裡我只介紹相對較為簡單的 for 語句。

1、語法規則

for 語句的一般形式為:

for(迴圈初始化表示式; 迴圈條件表示式; 迴圈執行表示式){
	迴圈體
}

它的執行過程為:

1)首先,執行 迴圈初始化表示式

2)然後,執行 迴圈條件表示式,如果它的值為真,則執行迴圈體,否則結束迴圈;

3)接著,執行完迴圈體後再執行 迴圈執行表示式

4)重複執行步驟 2)和 3),直到 迴圈條件表示式 的值為假,則結束迴圈。

上面的步驟中,2)和 3)是一次迴圈,會重複執行,for 語句的主要作用就是不斷執行步驟 2)和 3)。執行過程如下圖所示:

細心的讀者可能會發現,迴圈體迴圈執行表示式 其實是可以合併的,是的,的確是這樣。在下面的例子中我會講到。

2、簡單應用

接下來,我們就來實現一個最簡單的迴圈語句,求 1 + 2 + 3 + ... + n 的值。

int sumNums(int n){
	int i;
    int sum=0;
    for(int i=1;i<=n;i++){
		sum += i;
    }
    return sum;
}
  • 這是一個函式,傳參是 n,返回值為 1 + 2 + 3 + ... + n 的值;
  • 作為一個迴圈變數;
  • 初始化求和的值 s 為 0;
  • for 語句三部分:迴圈初始化表示式:i = 1;迴圈條件表示式:i <= n;迴圈執行表示式:++i;
  • 迴圈體:sum += i;,表示將 1、2、3、4、... 累加到 sum上;
  • 返回求和sum的值;

以上這段程式碼,實現了一個數學上的 等差數列 求和。也可以用公式來表示,如下:

而利用 for 迴圈,讓我們拋開了數學思維,用程式的角度來實現數學問題。注意,for 迴圈中的那個表示式都可以省略,但它們之間的 分號 必須保留。

3、初始化表示式

1)初始化表示式外接

我們可以把 初始化表示式 提到 for 迴圈外面,如下:

int i=1;
int sum=0;
for(;i<=n;i++){
	sum += i;
}

2)初始化表示式內建

我們也可以把需要的初始化資訊,都在初始化表示式內進行賦值,並且用逗號進行分隔,如下:

int i,sum;
for(int i=1,sum=0;i<=n;i++){
	sum += i;
}

4、條件表示式

如果省略 條件表示式,那就代表這個迴圈是一個死迴圈,如下:

int i;
int sum=0;
for(int i=1;;i++){
	sum += i;
}

這段程式碼表示這個迴圈沒有結束條件,那自然就不會結束了,編碼過程中應該儘量避免(當然,某些情況下還是需要的,例如遊戲開發中的主迴圈),或者,函式內部有能夠跳出函式的方法,比如 break 關鍵字。

5、執行表示式

執行表示式的作用是 讓迴圈條件 逐漸 不成立,從而跳出迴圈。 當然,它也是可以省略的,因為 迴圈體本身也是一個 語句塊,也可以達到類似功能,如下程式碼所示:

int i,sum=0;
for(i=1;i<=n;i++){
	sum += i;
    i++;
}

這段程式碼同樣達到了求和的功能,因為執行表示式被放入了迴圈體,這也正是上文所說的迴圈體和迴圈執行表示式合併的問題。

二、題目分析

1、2 的 冪

實現一個函式isPowerOfTwo,判斷一個 32位整型 是否是 2 的冪。

bool isPowerOfTwo(int n){
	int i;
    unsigned int k=1;
    if(n<=0)	return false;
    if(n==1)	return true;
    for(i=1;i<=21;i++){
		k *= 2;
        if(k==n)	return true;
    }
    return false;
}
  • (1) 定義一個無符號整型 ;
  • (2) 如果 n ≤ 0,則必然不是 2 的冪;
  • (3) 1 必然是 2 的 0 次冪;
  • (4) 列舉所有 2 的冪 2、4、8、16、... ;
  • (5) 一旦找到一個和 相等,返回true,則說明它是 2 的冪;
  • (6) 最後,沒有找到的話,返回false表示不是 2 的冪;

2、3 的冪

實現一個函式isPowerOfThree,判斷一個 32位整型 是否是 3 的冪。

bool isPowerOfThree(int n){
    int i;
    unsigned int k=1;
    if(n<=0)	return false;
    if(n==1)	return true;
    for(i=1;i<=20;i++){
		k *= 3;
        if(k==n)	return true;
    }
    return false;
}

和 2的冪 那一題相比,只改了兩個地方:

  • (1) 第一個是列舉的上限只需要到 20,因為 3 的 21 次冪超過 32位 整型的上限了;
  • (2) 第二個是每次列舉的是 1、3、9、27、...,所以 不斷乘 3。

3、4 的冪

實現一個函式isPowerOfFour,判斷一個 32位整型 是否是 4 的冪。

bool isPowerOfFour(int n){
    int i;
    unsigned int k=1;
    if(n<=0)	return false;
    if(n==1)	return true;
    for(i=1;i<=15;i++){
		k *= 4;
        if(k==n)	return true;
    }
    return false;
}

和 3的冪 那一題相比,只改了兩個地方:

  • (1) 第一個是列舉的上限只需要到 15,因為 4 的 16 次 超過 32位 整型的上限了;
  • (2) 第二個是每次列舉的是 1、4、16、...,所以 k 不斷乘 4。

4、n 的第 k 個因子

給你兩個正整數n 和k 。如果正整數 i滿足 n % i == 0,那麼我們就說正整數 i是整數 n的因子。考慮整數 n的所有因子,將它們 升序排列 。請你返回第 k個因子。如果 的因子數少於 k,請你返回-1 。

int kthFactor(int n,int k){
    int i;
    int cnt=0;
    for(i=1;i<=n;i++){
		if(n%i==0){
            cnt++;
            if(cnt==k)	return i;
        }	
    }
    return -1;
}
  • (1) 定義一個計數器cnt,初始化為 0;
  • (2) 列舉所有範圍在 [1, n] 的數,因為只有這些數才可能是 的因子;
  • (3) 一旦滿足 n % i == 0,則計數器加一;
  • (4) 當計數器等於 k,則代表找到了 第 k 個因子,直接返回即可;
  • (5) 如果一直沒有找到,則表示不存在 第 k 個因子,返回 -1;

5、有效的完全平方數

給定一個 正整數 ,編寫一個函式,如果 是一個完全平方數,則返回true,否則返回 false。

int isPerfectSquare(int x){
    int i;
    long long p;
    for(i=1;;i++){
		p = (long long)i*i;
        if(p==x)	return true;
        if(p>x)		return false;
    }
    return false;
}
  • (1) 定義一個死迴圈,列舉所有數;
  • (2) 列舉所有數的平方,並且注意用 long long 避免 32整型溢位;
  • (3) 如果發現某個數的平方正好等於 x,則直接返回true;
  • (4) 如果發現列舉的數已經大於 x,無須再往下列舉,直接返回false;
  • (5) 這段程式碼是保底,理論上不可能跑到;

三、課後習題

1、求1+2+…+n

1+2+...+n ,要求不能使用乘除法、for、while、if、else、switch、case等關鍵字及條件判斷語句(A?B:C)。

class Solution {
public:
    int sumNums(int n) {
        long long sum=0;	//記得開long long防止超時
        for(int i=1;i<=n;i++){
            sum += i;
        }
        return sum;
    }
};

2、2 的冪

給你一個整數 n,請你判斷該整數是否是 2 的冪次方。如果是,返回 true ;否則,返回 false 。

如果存在一個整數 x 使得 n == 2x ,則認為 n 是 2 的冪次方。

class Solution {
public:
    bool isPowerOfTwo(int n) {
        if(n<=0)    return false;
        if(n==1)    return true;
        int p=1;
        for(int i=1;i<=30;i++){
            p *= 2;
            if(p==n)    return true;
        }
        return false;
    }
};

3、3的冪

給定一個整數,寫一個函式來判斷它是否是 3 的冪次方。如果是,返回 true ;否則,返回 false 。

整數 n 是 3 的冪次方需滿足:存在整數 x 使得 n == 3x

class Solution {
public:
    bool isPowerOfThree(int n) {
        if(n<=0)    return false;
        if(n==1)    return true;
        int p=1;
        for(int i=1;i<=19;i++){		//極限確定範圍
            p *= 3;
            if(p==n)    return true;
        }
        return false;
    }
};

4、4的冪

給定一個整數,寫一個函式來判斷它是否是 4 的冪次方。如果是,返回 true ;否則,返回 false 。

整數 n 是 4 的冪次方需滿足:存在整數 x 使得 n == 4x

class Solution {
public:
    bool isPowerOfFour(int n) {
        if(n<=0)    return false;
        if(n==1)    return true;
        int p=1;
        for(int i=1;i<=15;i++){
            p *= 4;
            if(p==n)    return true;
        }
        return false;
    }
};

5、n 的第 k 個因子

給你兩個正整數 n 和 k 。

如果正整數 i 滿足 n % i == 0 ,那麼我們就說正整數 i 是整數 n 的因子。

考慮整數 n 的所有因子,將它們 升序排列 。請你返回第 k 個因子。如果 n 的因子數少於 k ,請你返回 -1 。

class Solution {
public:
    int kthFactor(int n, int k) {
        int cnt=0;
        for(int i=1;i<=n;i++){
            if(n%i==0)  cnt++;
            if(cnt==k)  return i;
        }
        return -1;
    }
};
//這個題目就是看樣例,不需要考慮重複的因子,需要從小到大判斷出所有的因子,從而避免排序

6、有效的完全平方數

給定一個 正整數 num ,編寫一個函式,如果 num 是一個完全平方數,則返回 true ,否則返回 false 。

進階:不要 使用任何內建的庫函式,如 sqrt 。

class Solution {
public:
    bool isPerfectSquare(int num) {
        for(int i=1;i<=46340;i++){		//注意這個46430的平方是最靠近2147483647的完全平方數
            if(i*i==num)    return true;
        }
        return false;
    }
};