美丽的神话 发表于 2024-8-7 18:20:31

LeetCode 149, 347, 31

149. 直线上最多的点数

标题链接

149. 直线上最多的点数
标签

多少 数组 哈希表 数学
思路

总体思路

本题是一道 数学题,可以采取 暴力 的方式:


[*]先 罗列所有由两点连接而成的直线,即 罗列任意两个点 计算其所在直线。
[*]然后再 罗列所有点,统计 每条直线上的点的数量 的最大值。
可以轻微对这种方式进行优化:


[*]将第一步中的 罗列任意两个点 改为 罗列 任意点 和 其之后的所有点。防止 计算完点                                       A                                  A                     A 和点                                       B                                  B                     B 所在直线上的点的数量之后,再计算点                                       B                                  B                     B 和点                                       A                                  A                     A 所在直线上的点的数量 如许的重复计算。
[*]将第二步中的 罗列所有点 改为 罗列 第一步罗列的两个点之后的 所有点。制止了重复计算。
如何判断 一个点 在 由两点确定的直线 上

接下来就需要思量如何判断一个点 在 由两点确定的直线 上,其实并不难,既然已经罗列出两个点                                              P                            1                                  (                                 x                            1                                  ,                                 y                            1                                  )                         ,                                 P                            2                                  (                                 x                            2                                  ,                                 y                            2                                  )                              P_1(x_1, y_1), P_2(x_2, y_2)                  P1​(x1​,y1​),P2​(x2​,y2​),对于第三个点                                              P                            3                                  (                                 x                            3                                  ,                                 y                            3                                  )                              P_3(x_3, y_3)                  P3​(x3​,y3​),只要 第一个点 和 第二个点 所确定直线的斜率 与 第二个点 和 第三个点 所确定直线的斜率 雷同,则点                                              P                            3                                       P_3                  P3​ 在直线                                              P                            1                                          P                            2                                       P_1P_2                  P1​P2​ 上。斜率雷同可以表现如下:
                                                                           x                                     1                                              −                                             x                                     2                                                                               y                                     1                                              −                                             y                                     2                                                             =                                                                x                                     2                                              −                                             x                                     3                                                                               y                                     2                                              −                                             y                                     3                                                                   \frac{x_1 - x_2}{y_1 - y_2} = \frac{x_2 - x_3}{y_2 - y_3}                     y1​−y2​x1​−x2​​=y2​−y3​x2​−x3​​
但是,在程序中无法使用 int, double 表现分数,如果强行使用,则会造成一定的精度丧失,导致结果错误。以是思量 将 除法 酿成 乘法,斜率雷同表现如下:
                                       (                                       y                               2                                    −                                       y                               3                                    )                            (                                       x                               1                                    −                                       x                               2                                    )                            =                            (                                       x                               2                                    −                                       x                               3                                    )                            (                                       y                               1                                    −                                       y                               2                                    )                                  (y_2 - y_3) (x_1 - x_2) = (x_2 - x_3) (y_1 - y_2)                     (y2​−y3​)(x1​−x2​)=(x2​−x3​)(y1​−y2​)
确定第三个点是否在直线上时,需要多次使用                                    (                                 x                            1                                  −                                 x                            2                                  )                              (x_1 - x_2)                  (x1​−x2​) 和                                    (                                 y                            1                                  −                                 y                            2                                  )                              (y_1 - y_2)                  (y1​−y2​),以是用变量来纪录它们:                                 Δ                         x                         =                         (                                 x                            1                                  −                                 x                            2                                  )                         ,                         Δ                         y                         =                         (                                 y                            1                                  −                                 y                            2                                  )                              \Delta x = (x_1 - x_2), \Delta y = (y_1 - y_2)                  Δx=(x1​−x2​),Δy=(y1​−y2​),斜率雷同表现如下:
                                       (                                       y                               2                                    −                                       y                               3                                    )                            Δ                            x                            =                            (                                       x                               2                                    −                                       x                               3                                    )                            Δ                            y                                  (y_2 - y_3) \Delta x = (x_2 - x_3) \Delta y                     (y2​−y3​)Δx=(x2​−x3​)Δy
代码

class Solution {
    public int maxPoints(int[][] points) {
      int n = points.length; // 获取数组中点的数量
      if (n <= 2) { // 如果点的数量小于等于 2
            return n; // 则直接返回点的数量即可
      }

      int res = 0; // 保存结果
      for (int i = 0; i < n; i++) {
            int[] p1 = points; // 第一个点

            for (int j = i + 1; j < n; j++) {
                int[] p2 = points; // 第二个点

                int deltaX = p1 - p2; // p1 和 p2 的横坐标的差值
                int deltaY = p1 - p2; // p1 和 p2 的纵坐标的差值
                // 统计有多少个点位于 p1 与 p2 所确定的直线上,初始值为 2 表示 p1 和 p2 位于这条直线上
                int cnt = 2;
                for (int k = j + 1; k < n; k++) {
                  int[] p3 = points; // 第三个点

                                        // 如果 p3 在 p1, p2 所确定的直线上,则点数加一
                  if ((p3 - p2) * deltaX == (p3 - p2) * deltaY) {
                        cnt++;
                  }
                }

                res = Math.max(res, cnt); // 更新最大值
            }
      }
      return res;
    }
}
347. 前 K 个高频元素

标题链接

347. 前 K 个高频元素
标签

数组 哈希表 分治 桶排序 计数 快速选择 排序 堆(优先队列)
思路

本题可以使用 优先队列,和 LeetCode 215. 数组中的第K个最大元素 很相似,都使用 小顶堆 来存放数组中优先级前 K 高的元素,不外本题中元素的优先级不是元素的值,而是元素的出现次数。
本题直接使用 Java 中的 PriorityQueue 优先队列,(用一个长度为 2 的数组作为范例参数)保存元素的值和出现次数。此外,需要在构造器中传入一个 比力器,定义优先队列内部存储的数据如何进行比力。
代码

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
      // 统计每个元素出现的次数,key 为元素的值,value 为元素出现的次数
      Map<Integer, Integer> cnt = new HashMap<>(nums.length);
      for (int num : nums) {
            cnt.put(num, cnt.getOrDefault(num, 0) + 1);
      }

      // 小顶堆,元素出现的次数越少,越靠近顶部。存放着数组中频率前 k 高的元素
      // 在 int[] 中存放了 2 个值,第一个值表示 元素的值,第二个值表示 元素出现的次数
      PriorityQueue<int[]> pq = new PriorityQueue<>((p1, p2) -> p1 - p2);
      for (Map.Entry<Integer, Integer> entry : cnt.entrySet()) { // 构建小顶堆
            int num = entry.getKey(), count = entry.getValue();
            if (pq.size() < k) { // 如果小顶堆中的元素少于 k 个
                pq.offer(new int[]{num, count}); // 则给其中添加元素
            } else if (count > pq.peek()) {
                // 此时元素个数等于 k 个,如果 当前元素的出现次数 大于 堆顶元素的出现次数
                pq.poll(); // 则移除堆顶元素
                pq.offer(new int[]{num, count}); // 将当前元素放入堆中
            }
      }

      // 构造结果数组并返回
      int[] res = new int;
      for (int i = 0; i < k; i++) {
            res = pq.poll();
      }
      return res;
    }
}
31. 下一个排列

标题链接

31. 下一个排列
标签

数组 双指针
思路

本题是 纯技巧题,只要会这个技巧便能解决本题,如果不会,最好将其 背 下来。这个技巧分为如下三步:
   
[*]寻找:

[*]在数组中,从右向左寻找 小于它右边的数 的数,将其称为 逆数。例如 中的 4。
[*]如果在数组中找到了 逆数,那么从 末了一个数 到 逆数 的下一个数,寻找一个 比 逆数 大 的数,将其称为 大数。例如 中的 6。

[*]互换:如果能找到 大数,则互换这两个数。
[*]反转:

[*]如果在数组中找到了 逆数,则将 逆数 的下一个数 到 末了一个数 的范围内的所有数进行反转操作。
[*]如果在数组中没有找到 逆数,则将整个数组都进行反转操作。

如果很难理解这个技巧,不妨来看看这个例子,至少知道它可以使用:
对于数组
-----------------------------------
寻找逆数和比逆数大的数,分别用 i, j 指向:

          ^^
          ij
-----------------------------------
交换 i, j 指向的数:

          ^
          i
-----------------------------------
反转 i + 1 之后的部分:

代码

class Solution {
    public void nextPermutation(int[] nums) {
      final int n = nums.length;

      // 从右往左扫描,直到找到一个 比它右边的数小的 数
      int i = n - 2;
      while (i >= 0 && nums >= nums) {
            i--;
      }

      // 如果在数组中找到了逆数
      if (i >= 0) {
            // 则 在 索引为 i + 1 的数 到 最后一个数 的范围内,寻找一个比逆数大的数
            int j = n - 1;
            while (j > i && nums >= nums) {
                j--;
            }

            // 交换它们
            swap(nums, i, j);
      }

                // 反转 i + 1 之后的部分
      reverse(nums, i + 1);
    }
    // 交换 nums 中索引 i, j 指向的元素
    private void swap(int[] nums, int i, int j) {
      int temp= nums;
      nums = nums;
      nums = temp;
    }
    // 从 start 开始反转 nums 数组
    private void reverse(int[] nums, int start) {
      int left = start, right = nums.length - 1;
      while (left < right) {
            swap(nums, left, right);
            left++;
            right--;
      }
    }
}

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: LeetCode 149, 347, 31