劍指offer(五):遞歸和循環(cpp)

上一篇:https://blog.csdn.net/qq_41345173/article/details/104235084

1. 跳臺階

一隻青蛙一次可以跳上1級臺階,也可以跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法(先後次序不同算不同的結果)。

    int jumpFloor(int number) {
        int pre=0, next=1, now=0;
        while(number--){
            now=pre+next;
            pre=next;
            next=now;
        }
        return now;
    }

2. 變態跳臺階

一隻青蛙一次可以跳上1級臺階,也可以跳上2級……它也可以跳上n級。求該青蛙跳上一個n級的臺階總共有多少種跳法。

    int jumpFloorII(int number) {
        int res=1;
        while(number>1){
            res *=2;
            number--;
        }
        return res;
    }

注意:此時有數學歸納法可知f(n)=2^(n-1)種跳法

3. 矩形覆蓋

我們可以用2*1的小矩形橫着或者豎着去覆蓋更大的矩形。請問用n個2*1的小矩形無重疊地覆蓋一個2*n的大矩形,總共有多少種方法?

    int rectCover(int number) {
        int pre = 0, next = 1, now = 0;
        while(number--){
            now = pre+next;
            pre = next;
            next = now;
        }
        return now;
    }

和第一題跳臺階一個道理,當n=1時右一種方法,n=2時有兩種方法,當n=n時,若選擇豎着放相當於f(n-1)的方法,若橫着放相當於f(n-2)的放法。故這是一個不完全符合斐波那契數列的數列

4. 矩陣中的路徑

題目鏈接: https://www.nowcoder.com/practice/

class Solution {
public:
    bool hasPathCore(char* matrix, int rows, int cols,int row,int col,char* str,int &pathLength,bool *visited){
        if(str[pathLength]=='\0')
            return true;
        bool hasPath = false;
        if(row>=0&&row<rows&&col>=0&&col<cols&&matrix[row*cols+col]==str[pathLength]&&!visited[row*cols+col]){
            ++pathLength;
            visited[row*cols+col] = true;
            hasPath = hasPathCore(matrix,rows,cols,row,col-1,str,pathLength,visited)||
                hasPathCore(matrix,rows,cols,row,col+1,str,pathLength,visited)||
                hasPathCore(matrix,rows,cols,row-1,col,str,pathLength,visited)||
                hasPathCore(matrix,rows,cols,row+1,col,str,pathLength,visited);
            if(!hasPath){
                --pathLength;
                visited[row*cols+col] = false;
            }
        }
        return hasPath;
    }
    bool hasPath(char* matrix, int rows, int cols, char* str)
    {
        if(matrix==nullptr||rows<1||cols<1||str==nullptr)
            return false;
        int len = rows*cols, i;
        bool *visited = new bool[len];
        memset(visited,0,len);
        int pathLength = 0;
        for(int row=0;row<rows;++row){
            for(int col=0;col<cols;++col){
                if(hasPathCore(matrix,rows,cols,row,col,str,pathLength,visited)){
                    return true;
                }
            }
        }
        delete []visited;
        return false;
    }
};

回溯法的典型應用,顯然遞歸要比迭代編碼方便的多。

5. 機器人的運動範圍

地上有一個m行和n列的方格。一個機器人從座標0,0的格子開始移動,每一次只能向左,右,上,下四個方向移動一格,但是不能進入行座標和列座標的數位之和大於k的格子。 例如,當k爲18時,機器人能夠進入方格(35,37),因爲3+5+3+7 = 18。但是,它不能進入方格(35,38),因爲3+5+3+8 = 19。請問該機器人能夠達到多少個格子?

class Solution {
public:
    int getDigitSum(int number){
        int sum=0;
        while(number>0){
            sum +=number%10;
            number /=10;
        }
        return sum;
    }
    bool check(int threshold, int rows, int cols, int row, int col, bool *visited){
        if(row>=0&&row<rows&&col>=0&&col<cols&&getDigitSum(row)+getDigitSum(col)<=threshold&&!visited[row*cols+col])
            return true;
        return false;
    }
    int movingCountCore(int threshold, int rows, int cols, int row, int col, bool *visited){
        int count=0;
        if(check(threshold,rows,cols,row,col,visited)){
            visited[row*cols+col] = true;
            count =1+ movingCountCore(threshold,rows,cols,row-1,col,visited)+
                movingCountCore(threshold,rows,cols,row+1,col,visited)+
                movingCountCore(threshold,rows,cols,row,col-1,visited)+
                movingCountCore(threshold,rows,cols,row,col+1,visited);
        }
        return count;
    }
    int movingCount(int threshold, int rows, int cols)
    {
        if(threshold<0||rows<=0||cols<=0)
            return 0;
        int len = rows*cols;
        bool *visited = new bool[len];
        memset(visited,0,len);
        int count = movingCountCore(threshold,rows,cols,0,0,visited);
        delete []visited;
        return count;
    }
};

和上一題一樣也是回溯法的典型應用,重點是破題,出發點爲起始點,然後 對每一個周邊點做判斷是否可行,若可行繼續判斷周邊值的周邊值之和,經過層層遞歸可得最終結果。

6.剪繩子

給你一根長度爲n的繩子,請把繩子剪成整數長的m段(m、n都是整數,n>1並且m>1),每段繩子的長度記爲k[0],k[1],…,k[m]。請問k[0]xk[1]x…xk[m]可能的最大乘積是多少?例如,當繩子的長度是8時,我們把它剪成長度分別爲2、3、3的三段,此時得到的最大乘積是18。

class Solution {
public:
    int cutRope(int number) {
        if(number<2)
            return 0;
        if(number==2)
            return 1;
        if(number==3)
            return 2;
        int product[number];
        product[0]=0,product[1]=1,product[2]=2,product[3]=3;
        int max;
        for(int i=4;i<=number;++i){
            max = 0;
            for(int j=1;j<=i/2;++j){
                int mid = product[j]*product[i-j];
                if(mid>max)
                    max = mid;
            }
            product[i] = max;
        }
        return max;
    }
};

動態規劃的巧妙應用,還有一種貪心算法,高明的設計思路,需要推導

發佈了39 篇原創文章 · 獲贊 7 · 訪問量 4381
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章