贪心算法、动态规划与 MPPI 算法结构相关力扣题目汇总

贪心算法、动态规划与 MPPI 算法结构相关力扣题目汇总

目录


一、总体理解

本文主要围绕三类算法结构进行整理:

  1. 贪心算法:每一步选择当前最优,并希望通过局部最优推出全局最优。
  2. 动态规划算法:将大问题拆解成小问题,通过状态转移复用已有结果。
  3. MPPI 相关算法结构:MPPI 本身不是力扣中的固定分类,但其核心结构包括随机采样、轨迹展开、代价累计、候选轨迹选择、有限时域滚动优化等,这些思想可以通过部分力扣题进行训练。

三者可以简单理解为:

text 复制代码
贪心:当前这一步怎么选最好?
动态规划:当前状态怎么由之前的状态推出来?
MPPI:采样很多条未来轨迹,计算代价,再选择或加权更新更优轨迹。

二、贪心算法相关力扣题

2.1 贪心算法核心思想

贪心算法的本质是:

每一步都选择当前看起来最优的方案,并且这个局部最优能够推出最终的全局最优。

常见题型如下:

类型 典型特征 常见做法
分配贪心 资源和需求匹配 小资源优先满足小需求
跳跃贪心 判断能否到达或最少跳几次 维护当前最远可达位置
区间贪心 区间选择、区间删除、区间合并 按右端点排序
字符串贪心 字符划分、字典序、局部截断 记录最后出现位置或单调栈
股票贪心 多次买卖求最大利润 所有上涨区间都累加
双向贪心 左右两边都有约束 左右各扫描一遍

2.2 贪心题目汇总

题号 题目 类型 难度 重点
455 分发饼干 分配贪心 简单 小饼干优先满足小胃口
55 跳跃游戏 跳跃贪心 中等 维护最远可达位置
45 跳跃游戏 II 跳跃贪心 中等 当前覆盖范围与下一跳范围
435 无重叠区间 区间贪心 中等 按右端点排序
452 用最少数量的箭引爆气球 区间贪心 中等 区间交集与右端点
763 划分字母区间 字符串贪心 中等 记录字符最后出现位置
134 加油站 环形贪心 中等 局部失败后更换起点
122 买卖股票的最佳时机 II 股票贪心 中等 所有上涨段都累加
406 根据身高重建队列 排序贪心 中等 先高后低插入
135 分发糖果 双向贪心 困难 左右两遍扫描

2.3 题目讲解:455. 分发饼干

题意

有一些孩子,每个孩子有一个胃口值 g[i]。有一些饼干,每块饼干有大小 s[j]。如果 s[j] >= g[i],这个孩子就可以被满足。

要求:最多能满足多少个孩子。

思路

先将孩子胃口和饼干大小都排序。

贪心策略:

用当前最小的饼干,去满足当前胃口最小的孩子。

这样可以尽量避免用大饼干去满足小胃口孩子,从而保留大饼干给后面胃口更大的孩子。

C++ 解法

cpp 复制代码
class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(), g.end());
        sort(s.begin(), s.end());

        int i = 0;
        int j = 0;
        int ans = 0;

        while (i < g.size() && j < s.size()) {
            if (s[j] >= g[i]) {
                ans++;
                i++;
                j++;
            } else {
                j++;
            }
        }

        return ans;
    }
};

复杂度

text 复制代码
时间复杂度:O(nlogn + mlogm)
空间复杂度:O(1)

2.4 题目讲解:55. 跳跃游戏

题意

给定数组 numsnums[i] 表示从位置 i 最多可以向后跳多少步。判断是否可以从下标 0 跳到最后一个位置。

思路

维护一个变量 maxReach,表示当前能够到达的最远位置。

从左到右遍历数组:

  • 如果 i > maxReach,说明当前位置根本无法到达,直接返回 false
  • 否则用当前位置更新最远可达范围:
cpp 复制代码
maxReach = max(maxReach, i + nums[i]);

C++ 解法

cpp 复制代码
class Solution {
public:
    bool canJump(vector<int>& nums) {
        int maxReach = 0;

        for (int i = 0; i < nums.size(); i++) {
            if (i > maxReach) return false;
            maxReach = max(maxReach, i + nums[i]);
        }

        return true;
    }
};

复杂度

text 复制代码
时间复杂度:O(n)
空间复杂度:O(1)

2.5 题目讲解:45. 跳跃游戏 II

题意

给定数组 nums,每个位置可以向后跳最多 nums[i] 步。求跳到最后一个位置所需的最少跳跃次数。

思路

这道题可以理解成 BFS 的贪心优化。

维护两个边界:

text 复制代码
curEnd:当前这一跳能够覆盖的最远边界
far:下一跳能够覆盖的最远边界

从左到右遍历,当遍历到 curEnd 时,说明当前这一跳覆盖范围已经走完,需要再跳一次。

C++ 解法

cpp 复制代码
class Solution {
public:
    int jump(vector<int>& nums) {
        int steps = 0;
        int curEnd = 0;
        int far = 0;

        for (int i = 0; i < nums.size() - 1; i++) {
            far = max(far, i + nums[i]);

            if (i == curEnd) {
                steps++;
                curEnd = far;
            }
        }

        return steps;
    }
};

复杂度

text 复制代码
时间复杂度:O(n)
空间复杂度:O(1)

2.6 题目讲解:435. 无重叠区间

题意

给定若干区间,删除最少数量的区间,使剩下的区间互不重叠。

思路

贪心策略:

每次优先保留右端点最小的区间。

因为右端点越小,后面留给其他区间的空间越大,越容易保留更多区间。

C++ 解法

cpp 复制代码
class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        sort(intervals.begin(), intervals.end(), [](auto& a, auto& b) {
            return a[1] < b[1];
        });

        int count = 1;
        int end = intervals[0][1];

        for (int i = 1; i < intervals.size(); i++) {
            if (intervals[i][0] >= end) {
                count++;
                end = intervals[i][1];
            }
        }

        return intervals.size() - count;
    }
};

复杂度

text 复制代码
时间复杂度:O(nlogn)
空间复杂度:O(1)

2.7 题目讲解:763. 划分字母区间

题意

给定字符串 s,尽可能多地划分字符串,使得每个字母最多只出现在一个片段中。

思路

先记录每个字符最后一次出现的位置。

从左到右扫描,维护当前片段必须覆盖到的最远位置 end

i == end 时,说明当前片段内所有字符的最后出现位置都已经被覆盖,可以在这里切开。

C++ 解法

cpp 复制代码
class Solution {
public:
    vector<int> partitionLabels(string s) {
        vector<int> last(26);

        for (int i = 0; i < s.size(); i++) {
            last[s[i] - 'a'] = i;
        }

        vector<int> ans;
        int start = 0;
        int end = 0;

        for (int i = 0; i < s.size(); i++) {
            end = max(end, last[s[i] - 'a']);

            if (i == end) {
                ans.push_back(end - start + 1);
                start = i + 1;
            }
        }

        return ans;
    }
};

复杂度

text 复制代码
时间复杂度:O(n)
空间复杂度:O(1)

三、动态规划相关力扣题

3.1 动态规划核心思想

动态规划的本质是:

把大问题拆成小问题,用之前算过的结果推出当前结果。

做动态规划题目时,最重要的是三步:

text 复制代码
1. 定义状态:dp[i] 或 dp[i][j] 表示什么?
2. 写状态转移:当前状态怎么由之前状态推出来?
3. 初始化和返回答案。

3.2 动态规划题目汇总

题号 题目 类型 难度 重点
70 爬楼梯 一维 DP 简单 斐波那契结构
746 使用最小花费爬楼梯 一维 DP 简单 最小代价
198 打家劫舍 一维 DP 中等 选或不选
213 打家劫舍 II 环形 DP 中等 拆成两个线性问题
322 零钱兑换 完全背包 中等 最少硬币数
518 零钱兑换 II 完全背包 中等 方案数
416 分割等和子集 01 背包 中等 是否能装满容量
494 目标和 01 背包 中等 正负号转背包
300 最长递增子序列 子序列 DP 中等 LIS
1143 最长公共子序列 二维 DP 中等 字符串匹配
64 最小路径和 网格 DP 中等 代价累计
62 不同路径 网格 DP 中等 路径数量
72 编辑距离 字符串 DP 困难 插入、删除、替换
121 买卖股票的最佳时机 股票 DP 简单 最低买入价
188 买卖股票的最佳时机 IV 股票 DP 困难 状态机

3.3 题目讲解:70. 爬楼梯

题意

每次可以爬 1 阶或 2 阶,问爬到第 n 阶有多少种方法。

思路

到第 i 阶有两种来源:

text 复制代码
从 i - 1 阶爬 1 阶
从 i - 2 阶爬 2 阶

所以状态转移为:

cpp 复制代码
dp[i] = dp[i - 1] + dp[i - 2];

C++ 解法

cpp 复制代码
class Solution {
public:
    int climbStairs(int n) {
        if (n <= 2) return n;

        int a = 1;
        int b = 2;

        for (int i = 3; i <= n; i++) {
            int c = a + b;
            a = b;
            b = c;
        }

        return b;
    }
};

复杂度

text 复制代码
时间复杂度:O(n)
空间复杂度:O(1)

3.4 题目讲解:198. 打家劫舍

题意

有一排房子,每个房子有一定金额。不能偷相邻房子,问最多能偷多少钱。

思路

对于第 i 个房子,有两种选择:

text 复制代码
偷当前房子:dp[i - 2] + nums[i]
不偷当前房子:dp[i - 1]

所以状态转移为:

cpp 复制代码
dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]);

C++ 解法

cpp 复制代码
class Solution {
public:
    int rob(vector<int>& nums) {
        int pre2 = 0;
        int pre1 = 0;

        for (int x : nums) {
            int cur = max(pre1, pre2 + x);
            pre2 = pre1;
            pre1 = cur;
        }

        return pre1;
    }
};

复杂度

text 复制代码
时间复杂度:O(n)
空间复杂度:O(1)

3.5 题目讲解:322. 零钱兑换

题意

给定硬币面额 coins 和总金额 amount,求凑成该金额所需的最少硬币数。如果不能凑成,返回 -1

思路

这是完全背包问题。

定义状态:

text 复制代码
dp[i] 表示凑成金额 i 所需的最少硬币数。

状态转移:

cpp 复制代码
dp[i] = min(dp[i], dp[i - coin] + 1);

C++ 解法

cpp 复制代码
class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        const int INF = 1e9;
        vector<int> dp(amount + 1, INF);
        dp[0] = 0;

        for (int i = 1; i <= amount; i++) {
            for (int coin : coins) {
                if (i >= coin) {
                    dp[i] = min(dp[i], dp[i - coin] + 1);
                }
            }
        }

        return dp[amount] == INF ? -1 : dp[amount];
    }
};

复杂度

text 复制代码
时间复杂度:O(amount × coins.size())
空间复杂度:O(amount)

3.6 题目讲解:416. 分割等和子集

题意

给定数组 nums,判断能否把数组分成两个子集,使两个子集的和相等。

思路

如果数组总和是奇数,一定无法分成两个和相等的子集。

如果总和是偶数,问题变成:

能否从数组中选出一些数,使它们的和等于 sum / 2

这是标准 01 背包问题。

定义状态:

text 复制代码
dp[j] 表示是否可以从已有数字中凑出和 j。

C++ 解法

cpp 复制代码
class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = 0;
        for (int x : nums) sum += x;

        if (sum % 2 != 0) return false;

        int target = sum / 2;
        vector<bool> dp(target + 1, false);
        dp[0] = true;

        for (int num : nums) {
            for (int j = target; j >= num; j--) {
                dp[j] = dp[j] || dp[j - num];
            }
        }

        return dp[target];
    }
};

复杂度

text 复制代码
时间复杂度:O(n × target)
空间复杂度:O(target)

3.7 题目讲解:300. 最长递增子序列

题意

给定数组 nums,求最长严格递增子序列的长度。

思路

定义状态:

text 复制代码
dp[i] 表示以 nums[i] 结尾的最长递增子序列长度。

状态转移:

text 复制代码
如果 nums[j] < nums[i],说明 nums[i] 可以接在 nums[j] 后面。

因此:

cpp 复制代码
dp[i] = max(dp[i], dp[j] + 1);

C++ 解法

cpp 复制代码
class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        int n = nums.size();
        vector<int> dp(n, 1);
        int ans = 1;

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < i; j++) {
                if (nums[j] < nums[i]) {
                    dp[i] = max(dp[i], dp[j] + 1);
                }
            }
            ans = max(ans, dp[i]);
        }

        return ans;
    }
};

复杂度

text 复制代码
时间复杂度:O(n²)
空间复杂度:O(n)

3.8 题目讲解:1143. 最长公共子序列

题意

给定两个字符串 text1text2,求它们最长公共子序列的长度。

思路

定义状态:

text 复制代码
dp[i][j] 表示 text1 前 i 个字符和 text2 前 j 个字符的最长公共子序列长度。

如果两个字符相同:

cpp 复制代码
dp[i][j] = dp[i - 1][j - 1] + 1;

否则:

cpp 复制代码
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);

C++ 解法

cpp 复制代码
class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
        int m = text1.size();
        int n = text2.size();

        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));

        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (text1[i - 1] == text2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }

        return dp[m][n];
    }
};

复杂度

text 复制代码
时间复杂度:O(mn)
空间复杂度:O(mn)

3.9 题目讲解:64. 最小路径和

题意

给定一个网格,每个格子有代价,只能向右或向下走,求从左上角到右下角的最小路径代价。

思路

定义状态:

text 复制代码
dp[i][j] 表示走到 grid[i][j] 的最小代价。

状态转移:

cpp 复制代码
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];

C++ 解法

cpp 复制代码
class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        int m = grid.size();
        int n = grid[0].size();

        vector<vector<int>> dp(m, vector<int>(n, 0));
        dp[0][0] = grid[0][0];

        for (int i = 1; i < m; i++) {
            dp[i][0] = dp[i - 1][0] + grid[i][0];
        }

        for (int j = 1; j < n; j++) {
            dp[0][j] = dp[0][j - 1] + grid[0][j];
        }

        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
            }
        }

        return dp[m - 1][n - 1];
    }
};

复杂度

text 复制代码
时间复杂度:O(mn)
空间复杂度:O(mn)

四、MPPI 算法结构相关力扣题

4.1 MPPI 算法基本流程

MPPI 的全称是:

text 复制代码
Model Predictive Path Integral Control

中文可以理解为:

text 复制代码
基于路径积分的模型预测控制。

MPPI 的典型流程如下:

text 复制代码
1. 获取当前状态 x0。
2. 随机采样多组控制序列 u。
3. 利用动力学模型 rollout 多条未来轨迹。
4. 对每条轨迹计算总代价 cost。
5. 根据代价给轨迹分配权重。
6. 用加权平均更新控制序列。
7. 执行第一个控制量。
8. 下一时刻重新规划。

从算法结构上看,MPPI 涉及以下几个核心模块:

MPPI 模块 对应编程结构 对应力扣题型
随机采样控制序列 随机数、权重采样 528、398、382、470
轨迹 rollout 路径搜索、状态扩展 64、63、1091、1631、787
代价函数累计 路径代价、风险惩罚 64、931、746
最优轨迹选择 最小代价、优先队列 743、787、1631
滚动优化窗口 滑动窗口、有限视野 239、862
障碍物避让 网格障碍、碰撞约束 63、1293、1091
多候选轨迹筛选 Top-K、堆、排序 215、347、973

4.2 MPPI 结构相关力扣题汇总

题号 题目 对应 MPPI 结构 难度
528 按权重随机选择 按权重采样控制序列 中等
398 随机数索引 随机采样、蓄水池采样 中等
382 链表随机节点 随机采样 中等
470 用 Rand7 实现 Rand10 随机数变换 中等
64 最小路径和 轨迹代价累计 中等
63 不同路径 II 障碍物约束 中等
1091 二进制矩阵中的最短路径 障碍物地图搜索 中等
1293 网格中的最短路径,带障碍消除 带约束状态扩展 困难
1631 最小体力消耗路径 路径代价最小化 中等
787 K 站中转内最便宜的航班 有限步长最优控制 中等
743 网络延迟时间 Dijkstra 最短路径 中等
239 滑动窗口最大值 滚动窗口优化 困难
215 数组中的第 K 个最大元素 候选轨迹筛选 中等
347 前 K 个高频元素 Top-K 筛选 中等
973 最接近原点的 K 个点 轨迹候选排序 中等

4.3 题目讲解:528. 按权重随机选择

为什么和 MPPI 有关?

MPPI 中,每条采样轨迹会根据代价分配权重:

text 复制代码
代价越低,权重越大;
代价越高,权重越小。

然后根据这些权重对控制序列进行加权更新。

力扣 528 练习的就是:

如何按照权重进行随机选择。

题意

给定权重数组 w,下标 i 被选中的概率为:

text 复制代码
w[i] / sum(w)

思路

先做前缀和:

text 复制代码
w = [1, 3, 2]
prefix = [1, 4, 6]

随机生成一个 [1, sum] 之间的整数,然后用二分查找找到它落在哪个区间。

C++ 解法

cpp 复制代码
class Solution {
private:
    vector<int> prefix;
    int total;

public:
    Solution(vector<int>& w) {
        total = 0;
        for (int x : w) {
            total += x;
            prefix.push_back(total);
        }
    }

    int pickIndex() {
        int target = rand() % total + 1;

        int l = 0;
        int r = prefix.size() - 1;

        while (l < r) {
            int mid = l + (r - l) / 2;
            if (prefix[mid] >= target) {
                r = mid;
            } else {
                l = mid + 1;
            }
        }

        return l;
    }
};

复杂度

text 复制代码
初始化时间复杂度:O(n)
单次采样时间复杂度:O(logn)
空间复杂度:O(n)

4.4 题目讲解:1631. 最小体力消耗路径

为什么和 MPPI 有关?

MPPI 会评估多条候选轨迹的总代价,例如:

text 复制代码
路径长度
障碍物距离
控制平滑性
能耗
风险代价
终点误差

这道题也是在网格中寻找一条代价最优的路径。

题意

给定高度地图 heights,从左上角走到右下角。路径的体力消耗定义为路径中相邻格子高度差的最大值。求最小体力消耗。

思路

这题可以用 Dijkstra 算法。

普通最短路是累加边权,而这道题路径代价是:

text 复制代码
当前路径中最大的高度差。

所以转移时:

cpp 复制代码
newCost = max(curCost, abs(heights[x][y] - heights[nx][ny]));

C++ 解法

cpp 复制代码
class Solution {
public:
    int minimumEffortPath(vector<vector<int>>& heights) {
        int m = heights.size();
        int n = heights[0].size();

        vector<vector<int>> dist(m, vector<int>(n, INT_MAX));
        dist[0][0] = 0;

        priority_queue<
            tuple<int, int, int>,
            vector<tuple<int, int, int>>,
            greater<tuple<int, int, int>>
        > pq;

        pq.push({0, 0, 0});

        vector<int> dx = {1, -1, 0, 0};
        vector<int> dy = {0, 0, 1, -1};

        while (!pq.empty()) {
            auto [cost, x, y] = pq.top();
            pq.pop();

            if (x == m - 1 && y == n - 1) return cost;
            if (cost > dist[x][y]) continue;

            for (int k = 0; k < 4; k++) {
                int nx = x + dx[k];
                int ny = y + dy[k];

                if (nx < 0 || nx >= m || ny < 0 || ny >= n) continue;

                int diff = abs(heights[x][y] - heights[nx][ny]);
                int newCost = max(cost, diff);

                if (newCost < dist[nx][ny]) {
                    dist[nx][ny] = newCost;
                    pq.push({newCost, nx, ny});
                }
            }
        }

        return 0;
    }
};

复杂度

text 复制代码
时间复杂度:O(mnlog(mn))
空间复杂度:O(mn)

4.5 题目讲解:787. K 站中转内最便宜的航班

为什么和 MPPI 有关?

MPPI 是有限时域控制,只在未来一段 horizon 内优化控制序列。

这道题是:

text 复制代码
只允许最多 K 次中转。

它对应的是:

有限步长内的最优代价搜索。

这和 MPC / MPPI 中的有限预测时域思想很像。

题意

n 个城市和若干航班,给定起点 src、终点 dst、最多中转次数 k,求最便宜价格。

思路

最多中转 k 次,最多乘坐 k + 1 条边。

可以使用 Bellman-Ford 的有限轮松弛。

每一轮表示多走一条边。

C++ 解法

cpp 复制代码
class Solution {
public:
    int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int k) {
        const int INF = 1e9;
        vector<int> dist(n, INF);
        dist[src] = 0;

        for (int step = 0; step <= k; step++) {
            vector<int> backup = dist;

            for (auto& f : flights) {
                int from = f[0];
                int to = f[1];
                int price = f[2];

                if (backup[from] != INF) {
                    dist[to] = min(dist[to], backup[from] + price);
                }
            }
        }

        return dist[dst] == INF ? -1 : dist[dst];
    }
};

复杂度

text 复制代码
时间复杂度:O(kE),E 为航班数量
空间复杂度:O(n)

4.6 题目讲解:1293. 网格中的最短路径,带障碍消除

为什么和 MPPI 有关?

MPPI 做移动机器人局部规划时,需要考虑障碍物约束、碰撞风险和状态扩展。

这道题练习的是:

text 复制代码
状态 = 位置 + 剩余消障次数。

类似于机器人规划中的:

text 复制代码
状态 = 位姿 + 速度 + 约束条件。

题意

给定一个网格,0 表示空地,1 表示障碍物。你最多可以消除 k 个障碍物,求从左上角到右下角的最短路径。

思路

普通 BFS 只需要记录位置:

text 复制代码
x, y

但这道题还要记录剩余可消除障碍数量:

text 复制代码
x, y, remain

因此访问数组也需要三维:

text 复制代码
visited[x][y][remain]

C++ 解法

cpp 复制代码
class Solution {
public:
    int shortestPath(vector<vector<int>>& grid, int k) {
        int m = grid.size();
        int n = grid[0].size();

        vector<vector<vector<bool>>> visited(
            m, vector<vector<bool>>(n, vector<bool>(k + 1, false))
        );

        queue<tuple<int, int, int, int>> q;
        q.push({0, 0, k, 0});
        visited[0][0][k] = true;

        vector<int> dx = {1, -1, 0, 0};
        vector<int> dy = {0, 0, 1, -1};

        while (!q.empty()) {
            auto [x, y, remain, step] = q.front();
            q.pop();

            if (x == m - 1 && y == n - 1) return step;

            for (int i = 0; i < 4; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];

                if (nx < 0 || nx >= m || ny < 0 || ny >= n) continue;

                int nextRemain = remain - grid[nx][ny];
                if (nextRemain < 0) continue;

                if (!visited[nx][ny][nextRemain]) {
                    visited[nx][ny][nextRemain] = true;
                    q.push({nx, ny, nextRemain, step + 1});
                }
            }
        }

        return -1;
    }
};

复杂度

text 复制代码
时间复杂度:O(mnk)
空间复杂度:O(mnk)

五、三类算法对比

算法 核心问题 典型思维 适合题型
贪心 当前怎么选最好? 局部最优推出全局最优 区间、跳跃、分配、股票
动态规划 当前状态怎么由过去推出? 记忆历史结果,避免重复计算 背包、路径、子序列、股票
MPPI 相关结构 从多条采样轨迹中选哪条最好? 采样、rollout、代价计算、加权更新 随机采样、路径搜索、Top-K、滑动窗口

进一步理解:

text 复制代码
贪心:不回头,每一步直接选当前最优。
动态规划:把所有子问题都算清楚,再推出最终答案。
MPPI:不枚举所有可能,而是随机采样很多条未来轨迹,用代价函数筛选更优轨迹。

六、推荐刷题路线

6.1 第一阶段:先掌握贪心

建议顺序:

text 复制代码
455 分发饼干
122 买卖股票的最佳时机 II
55 跳跃游戏
45 跳跃游戏 II
435 无重叠区间
452 用最少数量的箭引爆气球
763 划分字母区间
134 加油站
135 分发糖果

重点掌握:

text 复制代码
排序
最远覆盖
右端点优先
局部失败换起点
左右两遍扫描

6.2 第二阶段:掌握动态规划

建议顺序:

text 复制代码
70 爬楼梯
746 使用最小花费爬楼梯
198 打家劫舍
213 打家劫舍 II
322 零钱兑换
416 分割等和子集
494 目标和
300 最长递增子序列
1143 最长公共子序列
64 最小路径和
72 编辑距离

重点掌握:

text 复制代码
dp[i] 的含义
状态转移方程
初始化
空间优化
一维 DP
二维 DP
背包 DP

6.3 第三阶段:理解 MPPI 相关算法结构

建议顺序:

text 复制代码
528 按权重随机选择
64 最小路径和
63 不同路径 II
1091 二进制矩阵中的最短路径
1293 网格中的最短路径,带障碍消除
1631 最小体力消耗路径
787 K 站中转内最便宜的航班
239 滑动窗口最大值
215 数组中的第 K 个最大元素
347 前 K 个高频元素
973 最接近原点的 K 个点

重点掌握:

text 复制代码
随机采样
路径展开
代价累计
障碍约束
有限时域搜索
候选轨迹筛选
Top-K 筛选
滚动窗口优化

七、面向机器人/无人车算法理解的重点题目

如果是为了理解移动机器人、无人车、局部规划器、MPPI 等算法,下面这些题尤其有用:

题号 题目 对应机器人/MPPI思想
64 最小路径和 轨迹总代价累计
63 不同路径 II 障碍物约束
1091 二进制矩阵中的最短路径 栅格地图搜索
1293 网格中的最短路径,带障碍消除 带约束状态扩展
1631 最小体力消耗路径 路径风险/最大代价最小化
787 K 站中转内最便宜的航班 有限预测时域优化
528 按权重随机选择 基于权重的采样选择
239 滑动窗口最大值 滚动窗口优化结构
215 数组中的第 K 个最大元素 候选轨迹筛选
973 最接近原点的 K 个点 候选结果排序与筛选

八、最终总结

如果是为了面试刷题,重点刷:

text 复制代码
贪心:55、45、435、763、134
动态规划:198、322、416、300、1143、64、72
MPPI结构理解:528、64、1293、1631、787

如果是为了机器人/无人车/MPPI算法理解,重点关注:

text 复制代码
64 最小路径和:练代价累计
1631 最小体力消耗路径:练路径代价优化
787 K站中转内最便宜航班:练有限时域优化
1293 网格障碍消除:练带约束状态搜索
528 按权重随机选择:练基于权重的随机采样

一句话总结:

贪心练"局部选择",动态规划练"状态转移",MPPI相关题练"采样轨迹、代价评估、有限时域优化和候选轨迹筛选"。

相关推荐
战族狼魂2 小时前
每日一课:算法系统学习路线
人工智能·算法·大模型·大语言模型
变量未定义~2 小时前
连通块中点的数量、堆箱子(4星)
算法
j7~2 小时前
【算法】专题二:滑动窗口之水果成蓝,找到字符串中所有字⺟异位词等算法题
c++·算法·滑动窗口·水果成蓝·最小字串覆盖·优选算法精选
木木子222 小时前
# 星座配对深度解析:Select 长列表选择器、矩阵评分算法与数据驱动建议
java·算法·华为·矩阵·harmonyos
大鱼>2 小时前
AI+货物追踪:跨境电商包裹追踪系统
人工智能·深度学习·算法·机器学习
大鱼>2 小时前
AI+货物追踪:全链路货物可视化追踪系统
人工智能·深度学习·算法·机器学习
大江东去浪淘尽千古风流人物2 小时前
【SLAM】slam高动态位姿估计全链路拆解
算法·面试·职场和发展·视觉里程计·slam·vio·大疆
想你依然心痛2 小时前
量子计算对嵌入式密码学的挑战与后量子算法准备
算法·密码学·量子计算
小O的算法实验室3 小时前
2026年SEVC,集成 Q-learning 多目标优化算法+车辆灵活编组列车调度
算法