题目链接:零钱兑换

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

你可以认为每种硬币的数量是无限的。

方法一:动态规划 + 二维数组

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        int n = coins.size();
        vector f(n + 1, vector<int>(amount + 1, INT_MAX / 2));
        f[0][0] = 0;
        for (int i = 0;i < n;i++) {
            for (int j = 0;j <= amount;j++) {
                if (j < coins[i]) {
                    f[i+1][j] = f[i][j];
                }else {
                    f[i+1][j] = min(f[i][j],f[i+1][j-coins[i]] + 1);
                }
            }
        }
        int ans = f[n][amount];
        return ans < INT_MAX / 2 ? ans : -1;
    }
};

方法二:动态规划+一维数组

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        vector<int> f(amount + 1, INT_MAX / 2);
        f[0] = 0;
        for (int x : coins) {
            for (int i = x;i <= amount;i++) {
                f[i] = min(f[i],f[i-x] + 1);
            }
        }
        int ans = f[amount];
        return ans < INT_MAX / 2 ? ans : -1;
    }
};

题目链接:打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

方法一:动态规划

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

题目链接:杨辉三角

给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。

在「杨辉三角」中,每个数是它左上方和右上方的数的和。

方法一:动态规划

class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        vector<vector<int>> ans;
        ans.push_back({1});
        for (int i = 1;i < numRows;i++) {
            vector<int> tmp;
            for (int j = 0;j <= i;j++) {
                
                if (j == 0 || j == i) tmp.push_back(1);
                else {
                    tmp.push_back(ans[i-1][j-1] + ans[i-1][j]);
                }
            }
            ans.push_back(tmp);
        }
        return ans;
    }
};

题目链接:爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

方法一:动态规划

class Solution {
public:
    int climbStairs(int n) {
        int f[50];
        f[1] = 1;
        f[2] = 2;
        f[3] = 3;
        for (int i = 4;i <= n;i++) {
            f[i] = f[i-2] + f[i-1];
        }
        return f[n];
    }
};

方法二:递归

class Solution {
public:
    int nums[50] = {0};

    int f(int x) {
        if (x <= 2) return nums[x];
        if (nums[x] != 0) return nums[x];   // 关键:已经算过就直接返回

        nums[x] = f(x - 1) + f(x - 2);
        return nums[x];
    }

    int climbStairs(int n) {
        nums[1] = 1;
        nums[2] = 2;
        return f(n);
    }
};

题目链接:划分字母区间

给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。例如,字符串 "ababcc" 能够被分为 ["abab", "cc"],但类似 ["aba", "bcc"] 或 ["ab", "ab", "cc"] 的划分是非法的。

注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。

返回一个表示每个字符串片段的长度的列表。

方法一:贪心

class Solution {
public:
    vector<int> partitionLabels(string s) {
        int last[26];
        int end = 0,start = 0;
        for (int i = 0;i < s.size();i++) {
            last[s[i] - 'a'] = i;
        }
        vector<int> ans;
        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 = end+1;
            }
        }
        return ans;
    }
};