LeetCode-Solutions-in-Cpp17

Solutions to high-frequency interview questions of LeetCode in C++17, taking into account both efficiency and comprehensibility.


Project maintained by downdemo Hosted on GitHub Pages — Theme by mattgraham
class Solution {
 public:
  double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    vector<double> v;
    merge(begin(nums1), end(nums1), begin(nums2), end(nums2), back_inserter(v));
    int n = size(v);
    return (v[(n - 1) / 2] + v[n / 2]) / 2.0;
  }
};
假设操场上的学生排成两列队伍,两列队伍都是身高由矮到高排列
现在要从所有人中找出第 6 矮的学生,各抽出前 3 名学生,编号如下:

123###############  // 队伍 A
456###############  // 队伍 B

如果 3  6 矮,则第 6 矮的不会在 123 中,证明如下:
假设 3 是第 6 矮,则要有 5 个更矮的,12 两个,差 3 
6  3 高,3  6 之后都是更高的,6 之前只有 2 个,不可能满足条件
同理,既然 3 不可能是第 6 矮,3 之前的更不可能
A 0 2 3 5 6 9
B 1 4 7 8

k = 6 为例,第 6 小的元素为 5,如何二分查找到它?

k = 6 => k / 2 = 3
m1 = 3  // A范围的第 3 个元素
m2 = 7  // B范围的第 3 个元素
m1 < m2 => 排除 A 左侧 3 个元素

A 5 6 9
B 1 4 7 8

查找剩余范围第 3 小的元素(已排除 3 个)
k = 3 => k / 2 = 1
m1 = 5  // A 范围的第 1 个元素
m2 = 1  // B 范围的第 1 个元素
m1 > m2 => 排除 B 左侧 1 个元素

查找剩余范围第 2 小的元素(已排除 4 个)
A 5 6 9
B 4 7 8
k = 2 => k / 2 = 1
m1 = 5  // A 范围的第 1 个元素
m2 = 4  // B 范围的第 1 个元素
m1 > m2 => 排除 B 左侧 1 个元素

查找剩余范围第 1 小的元素(已排除 5 个)
A 5 6 9
B 7 8
显然取两者较小的首元素即可
12                  // 队伍 A(只有 2 个人,抽不出 3 个)
456###############  // 队伍 B

要找第 6 矮,12 可能是,但 456 不可能是,排除 456
class Solution {
 public:
  double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    if (empty(nums1) && empty(nums2)) {
      return 0;
    }
    int n = size(nums1) + size(nums2);
    if (n % 2 & 1) {
      return findK(nums1, nums2, 0, 0, (n + 1) / 2);
    }
    double x = findK(nums1, nums2, 0, 0, n / 2);
    double y = findK(nums1, nums2, 0, 0, n / 2 + 1);
    return (x + y) / 2.0;
  }

  // 查找 nums1 和 nums2 中第 k 小的值
  // a 为 nums1 查找范围的起点,b 为 nums2 查找范围的起点
  double findK(vector<int>& nums1, vector<int>& nums2, int a, int b, int k) {
    if (a >= size(nums1)) {     // nums1 越界
      return nums2[b + k - 1];  // nums2 中从 b 开始第 k 小的数即为结果
    }
    if (b >= size(nums2)) {     // nums2 越界
      return nums1[a + k - 1];  // nums2 中从 b 开始第 k 小的数即为结果
    }
    if (k == 1) {  // k 为 1 则直接取较小的首元素
      return min(nums1[a], nums2[b]);
    }
    int x = a + k / 2 - 1;  // 下列的 x + 1 - a 实际就是 k / 2
    int y = b + k / 2 - 1;  // 下列的 y + 1 - b 实际就是 k / 2
    if (x >= size(nums1)) {  // nums1 不够 k / 2 个元素,从 nums2 排除元素
      return findK(nums1, nums2, a, y + 1, k - (y + 1 - b));
    }
    if (y >= size(nums2)) {  // nums2 不够 k / 2 个元素,从 nums1 排除元素
      return findK(nums1, nums2, x + 1, b, k - (x + 1 - a));
    }
    if (nums1[x] <= nums2[y]) {  // num1 的较小,从 nums1 排除元素
      return findK(nums1, nums2, x + 1, b, k - (x + 1 - a));
    }
    // nums2 的较小,从 nums2 排除元素
    return findK(nums1, nums2, a, y + 1, k - (y + 1 - b));
  }
};
class Solution {
 public:
  double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    int n = size(nums1) + size(nums2);
    int x = (n + 1) / 2;
    int y = (n + 2) / 2;
    return (findK(nums1, nums2, 0, 0, x) + findK(nums1, nums2, 0, 0, y)) / 2.0;
  }

  // 查找 nums1 和 nums2 中第 k 小的值
  // a 为 nums1 查找范围的起点,b 为 nums2 查找范围的起点
  double findK(vector<int>& nums1, vector<int>& nums2, int a, int b, int k) {
    if (a >= size(nums1)) {     // nums1 越界
      return nums2[b + k - 1];  // nums2 中从 b 开始第 k 小的数即为结果
    }
    if (b >= size(nums2)) {     // nums2 越界
      return nums1[a + k - 1];  // nums2 中从 b 开始第 k 小的数即为结果
    }
    if (k == 1) {  // k 为 1 则直接取较小的首元素
      return min(nums1[a], nums2[b]);
    }
    int x = a + k / 2 - 1;
    int y = b + k / 2 - 1;
    if (x >= size(nums1)) {  // nums1 不够 k / 2 个元素,从 nums2 排除元素
      return findK(nums1, nums2, a, y + 1, k - k / 2);
    }
    if (y >= size(nums2)) {  // nums2 不够 k / 2 个元素,从 nums1 排除元素
      return findK(nums1, nums2, x + 1, b, k - k / 2);
    }
    if (nums1[x] <= nums2[y]) {  // num1 的较小,从 nums1 排除元素
      return findK(nums1, nums2, x + 1, b, k - k / 2);
    }
    // nums2 的较小,从 nums2 排除元素
    return findK(nums1, nums2, a, y + 1, k - k / 2);
  }
};
class Solution {
 public:
  double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    int n = size(nums1) + size(nums2);
    int x = (n + 1) / 2;
    int y = (n + 2) / 2;
    return (findK(nums1, nums2, 0, 0, x) + findK(nums1, nums2, 0, 0, y)) / 2.0;
  }

  // 查找 nums1 和 nums2 中第 k 小的值
  // a 为 nums1 查找范围的起点,b 为 nums2 查找范围的起点
  double findK(vector<int>& nums1, vector<int>& nums2, int a, int b, int k) {
    if (a >= size(nums1)) {     // nums1 越界
      return nums2[b + k - 1];  // nums2 中从 b 开始第 k 小的数即为结果
    }
    if (b >= size(nums2)) {     // nums2 越界
      return nums1[a + k - 1];  // nums2 中从 b 开始第 k 小的数即为结果
    }
    if (k == 1) {  // k 为 1 则直接取较小的首元素
      return min(nums1[a], nums2[b]);
    }
    int x = a + k / 2 - 1;
    int y = b + k / 2 - 1;
    int m1 = x < size(nums1) ? nums1[x] : INT_MAX;
    int m2 = y < size(nums2) ? nums2[y] : INT_MAX;
    return m1 < m2 ? findK(nums1, nums2, x + 1, b, k - k / 2)
                   : findK(nums1, nums2, a, y + 1, k - k / 2);
  }
};