个人技术分享


前言

一个本硕双非的小菜鸡,备战24年秋招,计划刷完hot100和剑指Offer的刷题计划,加油!
根据要求,每一道题都要写出两种以上的解题技巧。

一、300. 最长递增子序列(HOT100)

300. 最长递增子序列
Note:贪心+二分
通过维护一个数组,表示长度为 i 的最长上升子序列的末尾元素的最小值,用 len 记录目前最长上升子序列的长度。
循环遍历数组中的元素,如果当前元素 nums[i] 大于 vec[len],说明可以将 nums[i] 添加到当前的最长递增子序列的末尾,因此将 len 加 1,并将 nums[i] 赋值给vec[len]。
如果当前元素 nums[i] 小于 vec[len],说明 nums[i] 不能添加到当前的最长递增子序列的末尾。此时需要在 vec 中找到一个合适的位置来插入 nums[i],使得插入后的 vec 仍然是一个递增序列。通过二分查找找到第一个大于或等于 nums[i] 的元素的位置 pos,然后将 nums[i] 插入到 vec[pos + 1] 的位置。

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int len = 1;
        int size = nums.size();

        if (size == 0) return 0;

        vector<int> vec(size + 1, 0);

        vec[len] = nums[0];

        for (int i = 1; i < size; i++) {
            if (nums[i] > vec[len]) {
                vec[++len] = nums[i];
            } else {
                int left = 1, right = len, pos = 0;
                while (left <= right) {
                    int mid = left + (right - left) / 2;
                    if (vec[mid] < nums[i]) {
                        pos = mid;
                        left = mid + 1;
                    } else {
                        right = mid - 1;
                    }
                }
                vec[pos + 1] = nums[i];
            }
        }
        return len;
    }
};

Note:动态规划解题

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        if (nums.size() <= 1) return nums.size();
        //1. 确定dp数组(dp table)以及下标的含义
        //dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度
        vector<int> dp(nums.size(), 1);
        int res = 0;
        
        //2. 确定递推公式
        //dp[i] = max(dp[i], dp[j] + 1)

        //3. 确定dp数组初始化

        //4. 确定遍历顺序
        for (int i = 1; i < nums.size(); i++) {
            for (int j = 0; j < i; j++) {
                if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
            }
            res = dp[i] > res ? dp[i] : res;
        }

        //5. 确定推导dp数组
        return res;
    }
};

二、62. 不同路径(HOT100)

不同路径

Note:动态规划

class Solution {
public:
    int uniquePaths(int m, int n) {
        //1. 确定dp数组(dp table)以及下标的含义
        //机器人到达每个空格的路径数
        vector<vector<int>> dp(m, vector<int>(n, 0));

        //2. 确定递推公式
        //dp[i][j] = dp[i][j - 1] + dp[i - 1][j]

        //3. 确定dp数组初始化
        //dp[i][0] = 0, dp[0][j] = 0
        for (int i = 0; i < m; i++) dp[i][0] = 1;
        for (int i = 0; i < n; i++) dp[0][i] = 1; 

        //4. 确定遍历顺序
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++)
                dp[i][j] = dp[i][j - 1] + dp[i - 1][j];
        }

        //5. 确定推导dp数组
        return dp[m - 1][n -1];
    }
};

Note:数论方法,变为一个组合问题。
公式:在这里插入图片描述

class Solution {
public:
    int uniquePaths(int m, int n) {
        long long numerator = 1; // 分子
        int denominator = m - 1; // 分母
        int count = m - 1;
        int t = m + n - 2;
        while (count--) {
            numerator *= (t--);
            while (denominator != 0 && numerator % denominator == 0) {
                numerator /= denominator;
                denominator--;
            }
        }
        return numerator;
    }
};
# 总结
祝大家都能学有所成,找到一份好工作!