我正在解决以下问题:https://leetcode.com/problems/k-closest-points-to-origin/
简而言之,给定点列表,返回最接近原点的K,而K内的顺序无关紧要。我正在尝试使用Hoare的分区使用quickselect变体来解决此问题,但是对于特定的输入,它无法给出正确的答案,我无法弄清原因。 Hoare的分区逻辑本身是从维基百科复制的。点:[[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(所以现在left为3,right为7)。然后,left一直到7,由于do而right变成6,它作为分区返回。但这是不正确的,因为points [5]为[-73,74],points [6]为[-57,67](所以points [5]> points [6])。我认为应该将7作为分区返回。这导致最终溶液包含[-73,-74]而不是[-57,67]。有人可以帮我理解算法的哪一部分不正确/由于维基百科逻辑必须正确而不适用于此问题?
答案 0 :(得分:0)
定义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)
答案 1 :(得分:0)
不知道结果为何,但是既然是c#,为什么不简化代码。 定义返回距离的方法
$b64image = base64_encode(file_get_contents($file));
echo '<div style="display:none;"><div id="image'.$count.'"><img src="data:image/jpg;base64,'.$b64image.'"/><p>'.$image.'</p></div></div>';
echo '<li><span style="color:#666; font-weight:bold"> '.$count.' </span><a href="#" id="featherlight-image" data-featherlight="#image'.$count.'" download="'.$entry.'"><span style="color:#777AFF; font-weight:bold">'.$entry.'</span></a></li>';
然后使用linq:
private static double DistanceToCenter(int[] p)
{
return Math.Sqrt(p[0] ^ 2 + p[1] ^ 2);
}
这将为您提供按距离0.0排序的列表,然后首先选择k以打印出来。