【PHP解法==LeetCode查找类型问题3(距离计算)】447.回旋镖的数量 && 149.直线上最多的点数(hard)

447.回旋镖的数量

给定平面上 n 对不同的点,“回旋镖” 是由点表示的元组 (i, j, k) ,其中 i 和 j 之间的距离和 i 和 k 之间的距离相等(需要考虑元组的顺序)。

找到所有回旋镖的数量。你可以假设 n 最大为 500,所有点的坐标在闭区间 [-10000, 10000] 中。

示例:

输入:[[0,0],[1,0],[2,0]]
输出:2
解释:两个回旋镖为 [[1,0],[0,0],[2,0]][[1,0],[2,0],[0,0]]
class Solution {
    function numberOfBoomerangs($points) {
        //查找数
        $len = count($points);
        $num = 0;
        //取一个固定点,检测该固定点到其他点的距离
        for($i = 0;$i<$len;++$i){
            $distance = [];
            for($j = 0;$j<$len;++$j){
                if($j != $i){
                    $key = $this->dis($points[$i],$points[$j]);
                    if(isset($distance[$key])){
                        $distance[$key]++;
                    }else{
                        $distance[$key] = 1;
                    }
                    //echo 'i';print_r($points[$i]);
                    //echo 'j';print_r($points[$j]);
                    //echo 'dis',dis($points[$i],$points[$j]),'<br>';
                }
            }
            //print_r($distance);
            //取得的结果,两两成一对,每一对可以有两种可能,所以进行排列组合排列组合An(n-1)
            foreach ($distance as $v)
                if($v>1)
                    $num += $v*($v-1);
        }
        return $num;
    }
    function dis($a ,$b){
        //勾股定理,不开根号,防止出现浮点数
        return ($a[0]-$b[0])*($a[0]-$b[0]) + ($a[1]-$b[1])*($a[1]-$b[1]);
    }
}

149.直线上最多的点数(hard)

给定一个二维平面,平面上有 个点,求最多有多少个点在同一条直线上。

示例 1:

输入: [[1,1],[2,2],[3,3]]
输出: 3
解释:
^
|
|        o
|     o
|  o  
+------------->
0  1  2  3  4

示例 2:

输入: [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
输出: 4
解释:
^
|
|  o
|     o        o
|        o
|  o        o
+------------------->
0  1  2  3  4  5  6

该题与上题结题类似,均是求坐标上的点,但此时需要求在一直线上

要考虑有三种情况:平行于x轴,平行于y轴,坐标点重复情况

其他均可用斜率表示,用xy的比值做哈希查找表

/**
 * Definition for a point.
 * class Point(
 *     public $x = 0;
 *     public $y = 0;
 *     function __construct(int $x = 0, int $y = 0) {
 *         $this->x = $x;
 *         $this->y = $y;
 *     }
 * )
 */
class Solution {
    function maxPoints($points) {
//[[1,1],[2,2],[3,3]]
//[[2,3],[3,3],[-5,3]]
//[[1,1],[1,1],[2,2],[2,2]]
//[[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
        //查找数
        $len = count($points);
        $max = 0;//记录在同一直线点数最多的数
        for($i = 0;$i<$len;++$i){
            $distance = [0];//斜率比值哈希表
            $x = $y = 0;//记录平行点
            $common = 1;//记录重复点
            for($j = 0;$j<$len;++$j){
                if($j != $i){
                    $key = $this->dis($points[$i],$points[$j]);
                    if($key == 'x') $x++;
                    elseif($key == 'y') $y++;
                    elseif($key == 'same') $common++;
                    else{
                        if(isset($distance[$key]))
                            $distance[$key]++;
                        else
                            $distance[$key] = 1; 
                    }
                }
            }
            $num = max($x,$y,max($distance)) + $common;
            if($num > $max) $max = $num;
            //已经包含全部记录,无需继续检索
            if($num == $len) break;
        }
        return $max;
    }
    //求斜率比值/平行点/重复点
    function dis($a,$b){
        $x = $a->x - $b->x;
        $y = $a->y - $b->y;
        if($x == 0 && $y==0) return 'same';//重复点
        if( $x == 0 ) return 'x';//平行于x轴
        if( $y == 0 ) return 'y';//平行于y轴
        $div = $this->max_divisor($x,$y);
        return $x/$div.':'.$y/$div;
    }
    //求最大公约数
    function max_divisor($a, $b){
        if($b==0)
            return $a;
        else
            return $this->max_divisor($b,($a%$b));
    }
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值