1. 程式人生 > 其它 >Leetcode 447:Number of Boomerangs

Leetcode 447:Number of Boomerangs

技術標籤:演算法java資料結構leetcode面試

Leetcode 447:Number of Boomerangs

You are given n points in the plane that are all distinct, where points[i] = [xi, yi]. A boomerang is a tuple of points (i, j, k) such that the distance between i and j equals the distance between i and k (the order of the tuple matters).

Return the number of boomerangs.

說人話:

給定平面上 n 對互不相同的點 points ,其中 points[i] = [xi, yi] 。迴旋鏢是由點 (i, j, k) 表示的元組 ,其中 i 和 j 之間的距離和 i 和 k 之間的距離相等(需要考慮元組的順序)。

返回平面上所有迴旋鏢的數量。

幾個要點:

  • 點是不同的點
  • 點 i 是樞紐
  • 返回的是迴旋鏢的數量,不是具體的迴旋鏢
  • n == points.length
  • 1 <= n <= 500:說明我們可以接受 O(n2) 級別的演算法
  • points[i].length == 2
  • -104 <= xi, yi <= 104
    ,所以算距離的時候不會出現溢位

示例:

image-20210205104319203

[法1] 暴力法

思路
  • 遍歷所有點的情況
  • 三層迴圈,找到符合條件的元組
  • 記錄元組個數
程式碼
class Solution {
    public int numberOfBoomerangs(int[][] points) {

        int result = 0;

        //三層遍歷
        for(int a=0;a<points.length;a++){
            for(int b=0;b<points.length;b++){
                for(int c=0;c<points.
length;c++){ //A.B.C為三個不同的點 if( a!=b && a!=c && b!=c){ //A.B的距離 int distanceAB = (points[a][0]-points[b][0])*(points[a][0]-points[b][0])+ (points[a][1]-points[b][1])*(points[a][1]-points[b][1]); //A.C的距離 int distanceAC = (points[a][0]-points[c][0])*(points[a][0]-points[c][0])+ (points[a][1]-points[c][1])*(points[a][1]-points[c][1]); //距離相等則累加 if( distanceAB == distanceAC){ result++; } } } } } return result; } }
提交結果
image-20210205111651794
程式碼分析
  • 時間複雜度:O(n3)
  • 空間複雜度:O(1)
改進思路

因為 N 的級別為 500,所以我們可以接受 n2 的複雜度, n3 就太大了。我們需要想辦法將時間複雜度降為 O(n2) 甚至更低。

[法2] 查詢表靈活選擇鍵值

思路

我們可以發現題目中 點 i 其實是一個樞紐,那麼我們就可以對於每個 點 i,遍歷其他剩餘點到 點 i 的距離,然後看看相同距離的點有多少個,對這些相同距離的點進行排列組合 An2,就可以了。

整體思路如下:

  • 遍歷所有點 i
  • 對每一個點 i 記錄其他所有點與點 i 的距離,並記錄相同距離的點的個數
  • 對這些相同距離的點進行排列組合 An2
  • 累計所有的點 i 得到迴旋鏢的個數
程式碼
class Solution {
    public int numberOfBoomerangs(int[][] points) {

        int result = 0;

        //遍歷每一個點 i
        for(int i=0;i<points.length;i++){

            Map<Integer,Integer> map = new HashMap<>();

            //以 i 作為樞紐
            for(int j=0;j<points.length;j++){
                //記錄其他點到點 i 的距離
                if( i!=j ){
                    //距離的平方
                    int distance = 
                    (points[i][0]-points[j][0])*(points[i][0]-points[j][0]) + 
                    (points[i][1]-points[j][1])*(points[i][1]-points[j][1]);

                    //統計相同記錄的點的個數
                    Integer count = map.get(distance);
                    if(count !=null && count>0){
                        count++;
                        map.put(distance,count);
                    }else{
                        map.put(distance,1);
                    }
                }
            }

            //對這些相同距離的點進行排列組合
            Set<Integer> keys = map.keySet();
            for(Integer key: keys){
                Integer count = map.get(key);
                if(count != null && count >= 2){
                    result += (count)*(count-1);
                }
            }
        }
        return result;
    }
}
提交結果
image-20210205113016913
程式碼分析
  • 時間複雜度:O(n2)。
  • 空間複雜度:因為對於每一個點 i 操作完成後都會釋放 map,然後再申請,所以自始至終都只需要 O(n) 的輔助空間。
陷阱

本題中保證點的座標在 [-10000,10000] 的範圍內,所以算距離的時候不會發生整數溢位。如果沒有這個條件的話,最好算距離的時候轉為 long 或者 decimal 來進行計算,避免整數溢位。