c# - 与原点最近的 K 个点(K 个最小元素),hoare 的分区没有给出特定输入的正确答案
问题描述
我正在解决这个问题:https ://leetcode.com/problems/k-closest-points-to-origin/
简而言之,给定一个点列表返回最接近原点的 K,其中 K 中的顺序无关紧要。我正在尝试使用 Hoare 分区的 quickselect 变体来解决这个问题,但是对于特定的输入,它没有给出正确的答案,我无法弄清楚为什么。Hoare 的分区逻辑本身是从 wikipedia 复制的。
点数:[[68,97],[34,-84],[60,100],[2,31],[-27,-38],[-73,-74],[-55,-39], [62,91],[62,92],[-57,-67]] K:5
namespace N
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class Solution
{
private readonly Random rand = new Random();
public int[][] KClosest(int[][] points, int K)
{
var result = new List<int[]>();
KClosestHelper(points, 0, points.Count() - 1, K);
return points.Take(K).ToArray();
}
private void KClosestHelper(int[][] points,
int left,
int right,
int k)
{
if (left >= right) return;
var partitionIndex = Partition(points, left, right);
int leftLength = partitionIndex - left + 1;
if (k < leftLength)
{
KClosestHelper(points, left, partitionIndex - 1, k);
}
else if (k > leftLength)
{
KClosestHelper(points, partitionIndex + 1, right, k - leftLength);
}
}
private int Partition(int[][] arr, int left, int right)
{
//var randomIndex = rand.Next(left, right+1);
//swap(arr, left, randomIndex);
var pivot = arr[left];
left--;
right++;
while (true)
{
do
{
left++;
} while (AIsCloserThanB(arr[left], pivot));
do
{
right--;
} while (AIsFartherThanB(arr[right], pivot));
if (left >= right) return right;
swap(arr, left, right);
}
}
private bool AIsCloserThanB(int[] a, int[] b)
{
return a[0] * a[0] - b[0] * b[0] + a[1] * a[1] - b[1] * b[1] < 0;
}
private bool AIsFartherThanB(int[] a, int[] b)
{
return a[0] * a[0] - b[0] * b[0] + a[1] * a[1] - b[1] * b[1] > 0;
}
private void swap(int[][] arr, int i, int j)
{
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
public class MainClass
{
public static void Main()
{
var arr = new int[10][];
arr[0] = new[] { 68, 97 };
arr[1] = new[] { 34, -84 };
arr[2] = new[] { 60, 100 };
arr[3] = new[] { 2, 31 };
arr[4] = new[] { -27, -38 };
arr[5] = new[] { -73, -74 };
arr[6] = new[] { -55, -39 };
arr[7] = new[] { 62, 91 };
arr[8] = new[] { 62, 92 };
arr[9] = new[] { -57, -67 };
var s = new Solution();
var closest = s.KClosest(arr, 5);
foreach (var item in closest)
{
Console.Out.WriteLine(string.Join(",", item));
}
}
}
}
在使用 left ==3 和 right ==7 的 Partition 调用中进行调试时,首先交换 3 和 7(所以现在左边是 3,右边是 7)。然后left一直到7,并且由于do while right变成了6,它作为分区返回。但这是不正确的,因为 points[5] 是 [-73,74] 而 points[6] 是 [-57,67](所以 points[5] > points[6])。我认为 7 应该作为分区返回。这导致最终解决方案包含 [-73,-74] 而不是 [-57,67]。有人可以帮我理解算法的哪一部分不正确/不适用于这个问题,因为维基百科的逻辑必须是正确的?
解决方案
定义Point
类
public class Point
{
public int X;
public int Y;
}
现在将您的观点放入Point[] points
并执行简单的 linq 查询
var closest = points.OrderBy(p => p.X * p.X + p.Y * p.Y).Take(k);
如果您不需要完整排序的集合,最新版本的 .NET 足够智能,可以使用QuickSelect ,因此预期的复杂性应该是O(k log N)
推荐阅读
- r - 在 R 中加入/匹配数据帧
- git - 无法使用 git 命令将文件推送到 GitHub
- ios - 错误:无法解析构建文件:XCBCore.BuildFile
- java - 在不同线程中具有读取器和写入器的 Java 复制文件(使用 BlockingQueue)
- excel - Excel中的分组和求和
- c++ - C++ 套接字错误 C1083:无法打开包含文件:'unistd.h':没有这样的文件或目录
- windows - TFS Git 存储库在 Windows 命令提示符上不断询问凭据
- python - 访问字典时字符串索引必须是整数(错误)
- javascript - 在Vue中路由后未定义的auth0变量
- flutter - Flutter 中的原始触摸/滑动数据?与带有 Android Studio 的 Java 相比?