LintCode K个最近的点

题目

给定一些 points 和一个 origin,从 points 中找到 k 个离 origin 最近的点。
按照距离由小到大返回。如果两个点有相同距离,则按照x值来排序;若x值也相同,就再按照y值排序。

样例
给出 points = [[4,6],[4,7],[4,4],[2,5],[1,1]], origin = [0, 0], k = 3
返回 [[1,1],[2,5],[4,4]]

坐标点类

class Point {
    int x;
    int y;

    Point() {
        x = 0;
        y = 0;
    }

    Point(int a, int b) {
        x = a;
        y = b;
    }

    @Override
    public String toString() {
        return "[" + x + "," + y + "]";
    }
}

思路

  1. 计算距离^2,获得与点等长的数组,切距离与点的坐标一一对应。
  2. 循环k次,寻找k个最小距离,按照最小距离的下标,并记录最近距离点。
  3. 每次比较,都要交换距离调整和点在数组中的位置,防止丢失与重复。

代码

public static Point[] kClosest(Point[] points, Point origin, int k) {
        // Write your code here
        int[] distance = new int[points.length];
        //计算距离^2
        for (int i = 0; i < points.length; i++) {
            distance[i] = (points[i].x - origin.x) * (points[i].x - origin.x)
             + (points[i].y - origin.y) * (points[i].y - origin.y);
        }
        Point[] ps = new Point[k];
        //获取距离最近的k个坐标
        for (int i = 0; i < k; i++) {
            int min = distance[i];
            ps[i] = points[i];
            for (int j = i + 1; j < distance.length; j++) {
                if (min > distance[j]) {
                    min = distance[j];
                    //交换,调整对应距离值,防止重复
                    int t = distance[i];
                    distance[i] = distance[j];
                    distance[j] = t;
                    ps[i] = points[j];
                    //交换,调整对应坐标,防止重复
                    Point o = points[j];
                    points[j] = points[i];
                    points[i] = o;
                }

                if (min == distance[j]) {
                    if (points[i].x > points[j].x) {
                        ps[i] = points[j];
                        //交换,调整对应坐标,防止重复
                        Point o = points[j];
                        points[j] = points[i];
                        points[i] = o;
                    } else if (points[i].x == points[j].x) {
                        if (points[i].y > points[j].y) {
                            ps[i] = points[j];
                            //交换,调整对应坐标,防止重复
                            Point o = points[j];
                            points[j] = points[i];
                            points[i] = o;
                        }
                    }
                }
            }
        }
        return ps;
    }
### LintCode 31 题目解析与解决方案 LintCode 31 题目名称为“数组划分”(Partition Array),其目标是将一个整数数组按照给定的整数 `k` 进行划分,使得所有小于 `k` 的元素位于数组的左侧,所有大于等于 `k` 的元素位于数组的右侧。最终需要返回划分后左侧部分的长度。 #### 题目描述 给定一个整数数组 `nums` 和一个整数 `k`,要求重新排列数组中的元素,使得所有小于 `k` 的元素出现在数组的左侧,所有大于等于 `k` 的元素出现在数组的右侧。返回划分后左侧部分的长度。 --- #### 解题思路 此问题可以通过双指针法高效解决。核心思想是使用两个指针分别从数组的两端开始扫描: - 左指针 `left` 从左向右寻找第一个大于等于 `k` 的元素。 - 右指针 `right` 从右向左寻找第一个小于 `k` 的元素。 - 当找到满足条件的两个元素时,交换它们的位置。 - 重复上述过程,直到两个指针相遇。 这种方法的时间复杂度为 O(n),空间复杂度为 O(1)。 --- #### 实现代码 以下是基于 C++ 和 Java 的实现代码: ```cpp class Solution { public: /** * @param nums: The integer array you should partition * @param k: An integer * @return: The index after partition */ int partitionArray(vector<int> &nums, int k) { if (nums.empty()) return 0; int left = 0, right = nums.size() - 1; while (left <= right) { while (left <= right && nums[left] < k) left++; while (left <= right && nums[right] >= k) right--; if (left <= right) { swap(nums[left], nums[right]); left++; right--; } } return left; } }; ``` ```java public class Solution { /** * @param nums: The integer array you should partition * @param k: An integer * @return: The index after partition */ public int partitionArray(int[] nums, int k) { if (nums.length == 0) return 0; int left = 0, right = nums.length - 1; while (left <= right) { while (left <= right && nums[left] < k) left++; while (left <= right && nums[right] >= k) right--; if (left <= right) { int temp = nums[left]; nums[left] = nums[right]; nums[right] = temp; left++; right--; } } return left; } } ``` --- #### 示例分析 **输入:** ```plaintext nums = [3, 2, 2, 1], k = 2 ``` **输出:** ```plaintext 2 ``` **解释:** 经过划分后,数组可能变为 `[1, 2, 2, 3]` 或其他等效形式,其中前两个元素均小于 `k=2`。 --- #### 复杂度分析 - **时间复杂度**:O(n),其中 n 是数组的长度。每个元素最多被访问两次(一次由左指针,一次由右指针)。 - **空间复杂度**:O(1),算法仅使用了常量级别的额外空间。 --- #### 注意事项 1. 初始时需检查数组是否为空,若为空则直接返回 0。 2. 循环条件为 `left <= right`,确保在指针相遇时仍能正确处理最后一个待交换的元素。 3. 在每次交换后,记得更新指针位置(`left++` 和 `right--`)以避免死循环。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值