0
点赞
收藏
分享

微信扫一扫

【LeetCode 程序员面试金典(第 6 版)】第八章题目 08.01-08.05

一条咸鱼的干货 2022-01-23 阅读 38

面试题 08.01. 三步问题 - 力扣(LeetCode) (leetcode-cn.com)

三步问题。有个小孩正在上楼梯,楼梯有 n 阶台阶,小孩一次可以上 1 阶、2 阶或 3 阶。实现一种方法,计算小孩有多少种上楼梯的方式。结果可能很大,你需要对结果模 1000000007。

class Solution {
public:
    enum{MOD = (int)1e9+7};
    int waysToStep(int n) {
        vector<int>dp(4, 0);
        // 赋初值 
        dp[0] = 1; dp[1] = 1; dp[2] = 2; 
        // 遍历 
        for(int i = 3; i <= n; ++i){
            // 如果台阶个数为i,有三种情况可以到达i:
            //1. 通过第i-1级台阶1步到i
            //2. 通过第i-2级台阶2步到i 
            //3. 通过第i-3级台阶3步到i 
            // 需注意 因为MOD=1e9+7,所以int类型最多保存两个MOD不溢出。所以对于每次加法运算都要MOD一下。
            dp[3] = ( (dp[2] + dp[1]) % MOD + dp[0]) % MOD;
            // 为了节省空间,可以通过整体往前移动3位。因为对于第i级台阶方案数来说,最多只需要前3个台阶的方案数。
            dp[0] = dp[1]; 
            dp[1] = dp[2];
            dp[2] = dp[3];
        }
        // 如果n < 3 直接输出初始值即可
        return n < 3 ? dp[n] : dp[3];
    }// end waysToStep
};

面试题 08.02. 迷路的机器人 - 力扣(LeetCode) (leetcode-cn.com)

设想有个机器人坐在一个网格的左上角,网格 r 行 c 列。机器人只能向下或向右移动,但不能走到一些被禁止的网格(有障碍物)。设计一种算法,寻找机器人从左上角移动到右下角的路径。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gr7gXH9O-1642948367009)(assets/image-20220118141459-wfkiypp.png)]

网格中的障碍物和空位置分别用 1 和 0 来表示。

返回一条可行的路径,路径由经过的网格的行号和列号组成。左上角为 0 行 0 列。如果没有可行的路径,返回空数组。

class Solution {
public:
    typedef pair<short, short> pss;
    vector<vector<int>> pathWithObstacles(vector<vector<int>>& obstacleGrid) {
        //真坑呀,起点也不能走 
        if(obstacleGrid[0][0]) return vector<vector<int>>();
        int r = obstacleGrid.size(); int c = obstacleGrid[0].size();
        // 开辟 前驱二维数组 , pre[x][y] = (nx, ny) 表示(0,0)->(nx, ny)->(x, y) 是可行的 
        vector<vector<pss>>pre(r, vector<pss>(c, pss(-1,-1)));
        //标识(0,0)是可以被经过 
        pre[0][0] = pss(-2, -2);

        // 寻找每个点可以经过哪个点到达 
        for(int i = 0; i < r; ++i){
            for(int j = 0; j < c; ++j){
                // 障碍物 跳过,所有障碍物的点都不可能从(0,0)到达 
                if(1 == obstacleGrid[i][j]) continue;
                // 从(0, 0)可以到达(i-1,j),并且从(i-1,j)可以达到(i,j)的条件 
		// pre[i][j]!=(-1,-1):两重含义 1. 可以由(0,0)到达。2.(i,j)点不存在障碍物。
                if(i && pre[i - 1][j] != pss(-1, -1)){
                    pre[i][j] = pss(i - 1, j);
                }
                // 从(0, 0)可以到达(i,j-1),并且从(i,j-1)可以达到(i,j)的条件
                if(j && pre[i][j - 1] != pss(-1, -1)){
                    pre[i][j] = pss(i, j - 1);
                }
            }
        }
        vector<vector<int>>path;
        //通过前驱找到路径 
        int x = r - 1, y = c - 1;
        while(pre[x][y].first != -1){
            if(0 == x && 0 == y) break; 
            int nx = pre[x][y].first;
            int ny = pre[x][y].second;
            path.push_back(vector<int>{x, y});
            x = nx; y = ny;
        }
        // 从终点找到最后都没到起点 
        if(x != 0 || y != 0) {
            path.clear();
            return path;
        }
        path.push_back(vector<int>{0, 0});

        //路径翻转
        reverse(path.begin(), path.end());
        return path;
    }
};

面试题 08.03. 魔术索引 - 力扣(LeetCode) (leetcode-cn.com)

魔术索引。 在数组A[0…n-1]中,有所谓的魔术索引,满足条件A[i] = i。给定一个有序整数数组,编写一种方法找出魔术索引,若有的话,在数组A中找出一个魔术索引,如果没有,则返回-1。若有多个魔术索引,返回索引值最小的一个。

class Solution {
public:
    int findMagicIndex(vector<int>& nums) {
        for(int i = 0; i < nums.size(); ++i) {
            if(nums[i] == i) {
                return i;
            }
        }
        return -1;
    }
};

面试题 08.04. 幂集 - 力扣(LeetCode) (leetcode-cn.com)

幂集。编写一种方法,返回某集合的所有子集。集合中 不包含重复的元素

说明:解集不能包含重复的子集。

示例:

输入: nums = [1,2,3]
输出:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]

class Solution {
public:
    vector<vector<int>> subsets(vector<int>& nums) {
        // 二进制枚举 
        // 放入空子集 
        vector<vector<int>> ans;

        // 遍历每一个子集 s。 1 << n 表示 2 ^ n 
        for(int s = 0; s < 1 << nums.size(); ++s){
            vector<int> sub;
            // 获取每个子集 s 的元素 
            for(int pos = 0; pos < nums.size(); ++pos){
		// 第 pos 个数字被选择 ,也即 整数 s 的二进制表示中,从右向左第 pos 位是 1 。
                if(s >> pos & 1) {
                    sub.push_back(nums[pos]);
                }
            }
            ans.push_back(sub);
        }
        return ans;
    }
};

class Solution {
public:
//存储所有的子集
vector<vector<int>> ans; 

    // pos:表示第pos个元素。sub 表示从 0-pos 这些位置上的元素,所有选取的元素集合。nums仅做传值用,不修改。
    // 注意 sub 前面的 & 符号,这说明 整个递归过程共享这一个 sub 集合
    void dfs(int pos, vector<int>& sub, const vector<int>& nums){
	// pos == nums.size() 表示:0-nums.size()-1的nums.size()个元素都进行了判定。
	// 每个元素都进行了取舍判定,那么一定出现了一个新的子集
        if(pos == nums.size()) {
            ans.push_back(sub);
            return;
        }
	// 对于 第pos个元素。 
	// 1. 选取该元素,第pos个元素需要放入sub集合中。
        sub.push_back(nums[pos]);
	// 继续判断 第 pos + 1 个元素的取舍情况。
        dfs(pos + 1, sub, nums);
	// 2. 不选取该元素,由于前面放进去了,此时需要将其取出,而且一定会位于最后的元素(这里如果无法理解,一定要找实例,模拟就明白了)
        sub.pop_back();
	// 继续判断 第 pos + 1个元素的取舍情况 
        dfs(pos + 1, sub, nums); 
    }
    vector<vector<int>> subsets(vector<int>& nums) {
        vector<int> sub;
        dfs(0, sub, nums);
        return ans;
    }
};

面试题 08.05. 递归乘法 - 力扣(LeetCode) (leetcode-cn.com)

递归乘法。 写一个递归函数,不使用 * 运算符, 实现两个正整数的相乘。可以使用加号、减号、位移,但要吝啬一些。

class Solution {
public:
    //遍历 A 的二进制位,A不断右移,而后通过 A & 1获得最后一个二进制位 
    int binMul(int A, int depth, int B){
        // A 最多向右移动 30次 
        if(depth == 31) {
            return 0;
        }
        // 如果当前 A二进制的第 depth位为1 ,乘法才有值 
        if(A & 1) {
            int ans = 0;
            // 遍历 B的所有二进制位
            for(int i = 0; i < 31; ++i){
                //此时,B 二进制的第i位和A二进制的第depth位都是1,两者相乘为 2^i * 2^{depth} = 2^{i+depth} 
                //而 2的次幂 可以通过移位来获得 
                if(B >> i & 1) {
                    ans += 1 << (i + depth);
                }
            }
            //当前的值 加上后面的二进制的和 
            return ans + binMul(A >> 1, depth + 1, B);
        }
        // 如果当前 A二进制的第depth位为0,当前二进制位的乘法值为0,全靠后面的二进制位决定 
        return binMul(A >> 1, depth + 1, B);
    }
    int multiply(int A, int B) {
        return binMul(A, 0, B);
    }
};
class Solution {
public:
    int multiply(int A, int B) {
        int ans=0;
        long long a=max(A,B);
        long long b=min(A,B);
        while(b){
            if(b&1)ans+=a;
            b>>=1;
            a+=a;
        }
        return ans;
    }
};
举报

相关推荐

0 条评论