分类 LeetCode 下的文章

合并区间

给出一个区间的集合,请合并所有重叠的区间。

示例 1:
输入: [[1,3],[2,6],[8,10],[15,18]]
输出: [[1,6],[8,10],[15,18]]
解释: 区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

示例 2:
输入: [[1,4],[4,5]]
输出: [[1,5]]
解释: 区间 [1,4] 和 [4,5] 可被视为重叠区间。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-intervals

思路

  • 首先对特殊情况进行判断,int n=intervals.size(),如果n==0或者n==1那么无需合并,直接返回就可以了
  • 然后对intervals进行排序,排序规则为 按照开始位置从小到大进行排序,如果两个元素的开始位置相等,那么结束位置从大到小排序。
  • 准备工作做完后,开始正式合并区间。 ret.push_back({intervals[0][0],intervals[0][1]})先在返回结果ret中插入第一个元素,否则第二个无法比较。
  • 如果intervals中待合并元素的开始位置intervals[i][0]<ret.back()[1]那么判断,它结束的位置大于等于ret.back()[1],那么将ret.back()[i]更新为intervals[i][1],否则不做操作。
  • 如果intervals中待合并元素的开始位置intervals[i][0]>=ret.back()[1],那么直接将其插入到ret中即可
  • 最后,返回ret。

题解

class Solution {
public:
    vector<vector<int>> ret;
    static bool cmp(const vector<int> &a,const vector<int> &b){
        if(a[0]==b[0]){
            return a[1]>b[1];
        } else return a[0]<b[0];
    }
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        int n=intervals.size();
        if(n==0||n==1) return intervals;
        sort(intervals.begin(),intervals.end(),cmp);
        ret.push_back({intervals[0][0],intervals[0][1]});
        for(int i=0;i<n;i++){
            if(ret.back()[1]>=intervals[i][0]){
                if(ret.back()[1]<=intervals[i][1]){
                    ret.back()[1]=intervals[i][1];
                }
            } else{
                ret.push_back({intervals[i][0],intervals[i][1]});
            }
        }
        return ret;
    }
};

解码方法

问题描述

一条包含字母 A-Z 的消息通过以下方式进行了编码:

'A' -> 1
'B' -> 2
...
'Z' -> 26
给定一个只包含数字的非空字符串,请计算解码方法的总数。

示例 1:
输入: "12"
输出: 2
解释: 它可以解码为 "AB"(1 2)或者 "L"(12)。

示例 2:
输入: "226"
输出: 3
解释: 它可以解码为 "BZ" (2 26), "VF" (22 6), 或者 "BBF" (2 2 6) 。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/decode-ways

思路

作者:user8973
链接:https://leetcode-cn.com/problems/two-sum/solution/dong-tai-gui-hua-fen-lei-tao-lun-by-user8973/

题解

class Solution {
public:
    int numDecodings(string s) {
        int len = s.length();
        if (len == 0 || s[0] == '0') {
            return 0;
        }
        vector<int> dp(len + 1, 0);
        dp[0] = 1; dp[1]=1;
        for (int i = 1; i < len; i++) {
            if (s[i - 1] != '0') {
                int num = (s[i - 1] - '0') * 10 + (s[i] - '0');
                if (num >= 1 && num <= 26) {
                    dp[i + 1] = ((s[i] != '0') ? dp[i - 1] + dp[i] : dp[i - 1]);
                } else if (s[i] != '0') {
                    dp[i + 1] = dp[i];
                } else return 0;
            } else if (s[i] != '0') {
                dp[i + 1] = dp[i];
            } else return 0;
        }
        return dp[len];
    }
};

不同路径 II

问题描述

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

不同路径 II.png

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

说明:m 和 n 的值均不超过 100。

示例 1:
输入:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
输出: 2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:

  1. 向右 -> 向右 -> 向下 -> 向下
  2. 向下 -> 向下 -> 向右 -> 向右

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-paths-ii

思路

int n = obstacleGrid.size(); int m = obstacleGrid[0].size();
long long dp[n][m];注意这里用long long,用int可能会爆掉
dp[i][j]为到达obstacleGrid[i][j]的路径条数,如果obstacleGrid[i][j]==1,即obstacleGrid[i][j]为障碍物,dp[i][j]置为0;否则obstacleGrid[i][j]=obstacleGrid[i-1][j]+obstacleGrid[i][j-1];
要注意先将边界dp[i][j]单独拿出来计算。

题解

class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>> &obstacleGrid) {
        int n = obstacleGrid.size();
        if (n == 0) return 0;
        int m = obstacleGrid[0].size();
        long long dp[n][m];
        dp[0][0] = obstacleGrid[0][0] == 0 ? 1 : 0;
        for (int i = 1; i < n; i++) {
            dp[i][0] = obstacleGrid[i][0] == 1 ? 0 : dp[i - 1][0];
        }
        for (int j = 1; j < m; j++) {
            dp[0][j] = obstacleGrid[0][j] == 1 ? 0 : dp[0][j - 1];
        }
        for (int i = 1; i < n; i++) {
            for (int j = 1; j < m; j++) {
                dp[i][j] = obstacleGrid[i][j] == 1 ? 0 :dp[i-1][j]+dp[i][j-1];
            }
        }
        return dp[n-1][m-1];
    }
};

前 K 个高频元素

问题描述

给定一个非空的整数数组,返回其中出现频率前 k 高的元素。

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

示例 2:
输入: nums = [1], k = 1
输出: [1]

说明:
你可以假设给定的 k 总是合理的,且 1 ≤ k ≤ 数组中不相同的元素的个数。
你的算法的时间复杂度必须优于 O(n log n) , n 是数组的大小。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/top-k-frequent-elements

思路

首先,在元素与元素出现次数之间建立一个map映射;
然后申请一个pair<int,int>类型的vector,并将这些映射关系存入到vector中。
将vector中元素按照second(元素出现次数)从大到小排序。
最后,将前k个pair元素的first(元素值)存入到一个vector即可。

题解

class Solution {
public:
    static bool cmp(const std::pair<int, int> &left, const std::pair<int, int> &right) {
        return left.second > right.second;
    }
    vector<int> topKFrequent(vector<int> &nums, int k) {
        std::map<int, int> count;
        for(int i=0;i<nums.size();i++) count[nums[i]]++;
        vector<pair<int, int>> buf;
        for(auto each:count) buf.push_back(each);
        sort(buf.begin(), buf.end(), cmp);
        vector<int> ans;
        for (auto each:buf) {
            if (ans.size() < k) {
                ans.push_back(each.first);
            }
        }
        return ans;
    }
};

小菜鸡对map的理解

map是key-value的对应关系。

平时用的话,假如k-v都是int型,那么map<int,int> tmp即可。
map是自动有序的,是根据key递增的顺序进行排序的。

内部实现的简单化理解

可以把map想象成两部分:
第一部分-pair<int,int> buf这一部分是key-value;
第二部分-搜索二叉树,节点为pair类型。

假设现在有<3,4>,<4,10>,<7,6>,<6,4>,<4,2>
最开始搜索树是空的,建立根节点<3,4>;
下一个<4,10>的key=4>3,所以<4,10>为根节点<3,4>的右子树;
同理,<7,6>为<4,10>的右子树;
而6<7,所以<6,4>为<7,6>的左子树。
4出现在<4,10>的节点上,所以用2替换10;

FullSizeRender1.jpg