《剑指offer》练习及解析(C++代码)10-12(动态规划方法;二分法;回溯算法)

一.剑指Offer 10-I,10-II.斐波那契数列和跳台阶问题

《剑指offer》练习及解析(C++代码)10-12(动态规划方法;二分法;回溯算法)_第1张图片

《剑指offer》练习及解析(C++代码)10-12(动态规划方法;二分法;回溯算法)_第2张图片

其中跳台阶问题可以转换成求斐波那契数列问题,即:

当前台阶的跳法总数目=前1个台阶(用1次跳1台阶方法)的跳法数目+前2个台阶(用1次跳2台阶方法)的跳法数目

F(n) = F(n-1)+ F(n-2)

因此,有两种解法:

1.递归方法

将此问题,转换成俩个子问题,递归求解

缺点:重复计算一次跳一个台阶算法次数

性能:时间复杂度:O(n^2) 空间复杂度:O(1)

代码:

//Solution 
class Solution {
public:
    int numWays(int n) {
        int num_ways= 0;
        if(n==0)
            return num_ways+1;
        if(n<0)
            return num_ways;
        num_ways = numWays(n-1) + numWays(n-2);
        return num_ways;

    }
};

2.动态规划法

转换成斐波那契数列求法,只不过初始值分别为,a=1,b=1

sum=a+b;a=b;b=sum;即F(n)= F(n-1)+F(n-2);F(n-2)=F(n-1);F(n-1)=F(n);以此循环,直到n=N

性能:时间复杂度:O(n),空间复杂度:O(1)

代码:

//0ms:100,O(n); 5.8mb:100, O(1)
class Solution {
public:
    int numWays(int n) {
        int sum = 0;
        int n_1=1,n_2=1;
        if(n==0||n==1)
            return 1;
        for(int i=2;i<=n;i++)
        {
            sum = (n_1+n_2)%1000000007;
            n_1=n_2;
            n_2=sum;
        }
        return sum;
    }
};

 

二.剑指Offer 11.旋转数组的最小数字

《剑指offer》练习及解析(C++代码)10-12(动态规划方法;二分法;回溯算法)_第3张图片

1.遍历法

从0开始遍历,直到找到第一次非递增的位置,即被旋转数列的头部是最小值

性能:时间复杂度:O(n), 空间复杂度:O(n)

class Solution {
public:
    int minArray(vector& numbers) {
        int n =numbers.size();
        int i=0;
        if(n==1)
            return numbers[0];
        for(i=0;i<(n-1);i++)
        {
            if(numbers[i+1]

2.排序法

先对数组进行排序,排序后数组的最开始位置即最小数

性能:根据排序算法性能

class Solution {
public:
    int minArray(vector& numbers) {
        sort(numbers.begin(), numbers.end());
        return numbers[0];
    }
};

3.二分法

每次从中间位置开始,将数组分为俩部分,确定前后那部分存在最小值,循环

性能:时间复杂度:O(log(n)),空间复杂度:O(n)

class Solution {
public:
    int minArray(vector& numbers) {
        int size = numbers.size();
        if (size == 0) {
            return 0;
        }

        int left = 0;
        int right = size - 1;

        while (left < right) {
            int mid = left + (right - left) / 2;
            // int mid = left + ((right - left) >> 1);
            if (numbers[mid] > numbers[right]) {
                // [3, 4, 5, 1, 2],mid 以及 mid 的左边一定不是最小数字
                // 下一轮搜索区间是 [mid + 1, right]
                left = mid + 1;
            } else if (numbers[mid] == numbers[right]) {
                // 只能把 right 排除掉,下一轮搜索区间是 [left, right - 1]
                right--;
            } else {
                // 此时 numbers[mid] < numbers[right]
                // mid 的右边一定不是最小数字,mid 有可能是,下一轮搜索区间是 [left, mid]
                right = mid;
            }
        }
        return numbers[left];

    }
};

三.剑指Offer 12. 矩阵中的路径

直到达到条件

1.从一个初始位置开始

2.选择一个未走过的方向前进

3.如果还能继续前进,回到步骤2继续;如果确定无法达成条件,回溯到上一个可选择方向的节点,继续步骤2操作;

   如果达成条件,则返回;

代码:

class Solution {
    vector> dir = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
    bool dfs(vector>& board, vector>&vis, int i, int j, string& word, int idx){
        vis[i][j] = 1;
        if(idx == word.size()) return true;
        idx ++;
        for(auto xy : dir){
            int x = i + xy[0], y = j + xy[1];
            if(x < 0 || x >= board.size() || y < 0 || y >= board[0].size() || vis[x][y] || board[x][y] != word[idx - 1]) continue;
            else{
                if(dfs(board, vis, x, y, word, idx)) return true;
            }
        }
        vis[i][j] = 0;
        return false;
    }
public:
    bool exist(vector>& board, string word) {
        int m = board.size(), n = board[0].size();
        vector>vis(m, vector(n, 0));
        for(int i = 0; i < m; i ++){
            for(int j = 0; j < n; j ++){
                if(board[i][j] == word[0]){
                    if(dfs(board, vis, i, j, word, 1)) return true;
                }
            }
        }
        return false;
    }
};

 

你可能感兴趣的:(算法题,剑指Offer)