剑指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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章