2021-09-13剑指10-14

本文涵盖了面试中常见的技术题目,包括递归实现斐波那契数列、优化查找与排序算法(如二分查找和快速排序)、回溯法在迷宫问题的应用,以及动态规划解决切割绳子和二维数组初始化问题。深入解析了这些算法的时间复杂度和空间复杂度,并提供了示例代码和解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

面试题10

斐波那契数列,这题难度低,重点在于分析时间复杂度,以f(10)为例,画树状图。
1.递归
2.循环,避免重复计算
时间O(n),空间O(1),做表就是O(n)

class Solution {
public:
    int Fibonacci(int n) {
        vector<int> v={0,1};
        if(n<2)
            return v[n];
        int f1 = 0;
        int f2 = 1;
        int f0 = 0;
        for(int i=2; i<=n; ++i){
            f0 = f2;//f(n-1)存进f0
            f2 = f1 + f2;//f(n)=f(n-1)+f(n-2)
            f1 = f0;//f(n-1)代替原来的f(n-2)
        }
        return f2;
        //不断更新f(n-1)和f(n-2)
    }
};

面试题11

牛客网链接
查找:顺序、二分、哈希表、二叉排序树
排序:快排、冒泡、归并,冒泡和快排要能迅速手写
二分时间复杂度是logn,所以需要把时间复杂度从n减少到logn的时候可以考虑

思路1:
暴力遍历,O(n)

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        int ans = rotateArray[0];
        for(int i=0; i<rotateArray.size(); ++i){
            if(ans > rotateArray[i]){
                ans = rotateArray[i];
            }
        }
        return ans;
    }
};

思路2:
二分法:
如果有目标值target,那么直接让arr[mid] 和 target 比较即可。
如果没有目标值,一般可以考虑端点

考虑到剩下2个数的时候,mid是左边那个,所以更新左边的话是first = mid + 1,右边是last = mid
参考题解

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        int len = rotateArray.size();
        int first = 0, last = len-1;
        while(first < last){//最后剩下一个元素,是答案
            if(rotateArray[first] < rotateArray[last])
                //提前退出
                return rotateArray[first];
            int mid = (first + last)/2;
            //注意这个mid的位置,放在循环里面
            if(rotateArray[mid] < rotateArray[last])
                last = mid;
            if(rotateArray[mid] > rotateArray[last])
                first = mid+1;
            else{
                first += 1;              
            }
        }
        return rotateArray[first];
    }
};

面试题12

回溯法
一般来说dfs,bfs都可,这里用dfs,一般dfs好写点。
牛客网链接
参考题解

class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param matrix char字符型vector<vector<>> 
     * @param word string字符串 
     * @return bool布尔型
     */
    bool dfs(vector<vector<char> >& matrix, string word, int index, int i, int j){
        if( i<0 || i>=matrix.size() || j<0 || j>=matrix[0].size() || index>=word.length() || word[index] != matrix[i][j]){
            //这里,边界判断要写在matrix[i][j]前面,否则容易栈溢出
            return false;
        }
        if(index == word.length()-1)
            return true;
        //注意这行,到这里如果word每个字符扫描完了,就返回true,上面已经判断word[index]==matrix[i][j]
        auto tmp = matrix[i][j];
        matrix[i][j] = '.';
        //这个改'.'是因为进了一个格子以后不能再进这个格子
        bool ans = (dfs(matrix, word, index+1, i-1, j) ||
            dfs(matrix, word, index+1, i+1, j) ||
            dfs(matrix, word, index+1, i, j-1) ||
            dfs(matrix, word, index+1, i, j+1));
        matrix[i][j] = tmp;
        return ans;
    }
    
    bool hasPath(vector<vector<char> >& matrix, string word) {
        // write code here
        for(int i=0; i<matrix.size(); ++i)
            for(int j=0; j<matrix[0].size(); ++j){
                //对每个点做深搜
                if(dfs(matrix, word, 0, i, j))
                    return true;
            }
        return false;
    }
};

面试题13

牛客网链接
初始化二维数组
vector<vector> v(rows, vector(cols, 0));

  • 思路:
    和上题类似,DFS,建立一张rows * cols的表,先算每个点能否进入,用getIn函数,能进入的点为1,不能的为0,然后dfs,从(0,0)遍历,访问过的点改为2,即为能到达的点。
    最后再扫描一次表,把值为2的点计数。
    时间O(m * n)
    空间O(m * n)
class Solution {
public:
    bool getIn(int threshold, int rows, int cols){
        int sum = 0;
        while(rows > 0){
            sum += rows % 10;
            rows /= 10;
        }
        while(cols > 0){
            sum += cols % 10;
            cols /= 10;
        }
        return sum <= threshold;
    }
    
    void dfs(int row, int col, vector<vector<int>> &v){
        if(row < 0 || row >= v.size() || col < 0 || col >= v[0].size())
            return;
        if(v[row][col] == 2)
            return;
        //注意这个退出点,访问过的不用再访问,否则容易无限循环
        if(v[row][col] != 0){
            v[row][col] = 2;
            dfs(row-1, col, v);
            dfs(row+1, col, v);
            dfs(row, col-1, v);
            dfs(row, col+1, v);
        }
    }
    
    int movingCount(int threshold, int rows, int cols) {
        if(rows == 0 || cols == 0)
            return 0;
        vector<vector<int>> v(rows, vector<int>(cols, 0));
        for(int i=0; i<rows; ++i){
            for(int j=0; j<cols; ++j){
                if(getIn(threshold, i, j))
                    v[i][j]=1;
                else
                    v[i][j]=0;
            }
        }
        //v[0][0] = 2;
        dfs(0, 0, v);
        int count = 0;
        for (int i=0; i<rows; ++i){
            for (int j=0; j<cols; ++j){
                if(v[i][j] == 2)
                    count += 1;
            }
        }
        return count;
    }
};

面试题14

显然可以动态规划,这里用自底向上效率更高,一般来说都是自底向上效率高。
建一个长度为n的数组,存储f(n),从1到n-1计算max(f(i)xf(n-i))
先把前几个值存进去
两层循环能看出,时间复杂度O(n²),空间复杂度O(n)
牛客网地址

class Solution {
public:
    int cutRope(int number) {
        vector<int> ans(number+1);//注意答案直接放在表里面
        ans[1]=1;
        ans[2]=2;
        ans[3]=3;
        for(int i=4;i<=number;++i){
            int max = 0;
            for(int j=1;j<i;++j){
                if(max < ans[j] * ans[i-j])
                    max= ans[j] * ans[i-j];
            }
            
            if(max < i) max=i; //和不剪的情况比较,取大的
            ans[i]=max;
        }
        return ans[number];
    }
};

贪心:思路见书
试探就是5以后都要切一刀3能保证最大,这个试探做到7就可以了
切3以后3种情况,2,3,4,分别处理,实际只有切出来以后剩了4需要单独处理

class Solution {
public:
    int cutRope(int number) {
        if(number == 2)
            return 2;
        if(number == 3)
            return 3;
        if(number == 4)
            return 4;
        int timesOf3 = number/3;
        if(number - timesOf3 * 3 == 1)
            timesOf3 -= 1;//处理切3以后剩余4的情况
        int ans1 = pow(3, timesOf3);//3的倍数乘积
        int ans2 = number - 3 * timesOf3;
        if(ans2 == 0) ans2 = 1;//剩余的乘积,如果是0,则设为1,否则剩余2保留,剩余4保留,切2+2和4一样
        return ans1*ans2;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值