【Leetcode】447. Number of Boomerangs

【Leetcode】447. Number of Boomerangs

class Solution1(object):
    def numberOfBoomerangs(self, points):
        """
        first method is brute force , get all three tuple combination and calc whether condition is matched
        TLE
        """
        result = 0
        for i in range(len(points)):
            for j in range(len(points)):
                if i == j: continue
                for k in range(len(points)):
                    if j == k: continue
                    if self.calc_distance(points[i], points[j]) == self.calc_distance(points[i], points[k]):
                        result += 1
        return result


    def calc_distance(self, point1, point2):
        return pow(point1[0] - point2[0], 2) + pow(point1[1] - point2[1], 2)


class Solution2(object):
    def numberOfBoomerangs(self, points):
        """
        use distance between two points as key, and the number of point pair as value, in each round , we build a new map for current point
        for each point we calc how many other point with the same distance to it , and they(other points) can form a triple
        and it's not necessary to judge whether i == j
        beat 10%
        """
        result = 0
        from collections import defaultdict
        for i in range(len(points)):
            dict = defaultdict(int)
            for j in range(len(points)):
                if i == j: continue
                dict[self.calc_distance(points[i], points[j])]  += 1
            for key in dict:
                    result += dict[key] * (dict[key] -1)
        return result

    def calc_distance(self, point1, point2):
        return pow(point1[0] - point2[0], 2) + pow(point1[1] - point2[1], 2)



class Solution3(object):
    def numberOfBoomerangs(self, points):
        """
        Try not import other package and other function but not faster
        beat 5%
        """
        result = 0
        for i in range(len(points)):
            dict = {}
            for j in range(len(points)):
                dict[self.calc_distance(points[i], points[j])] = dict.get(self.calc_distance(points[i], points[j]), 0) +1
            for key in dict:
                result += dict[key] * (dict[key] -1)
        return result
    def calc_distance(self, point1, point2):
        return (point1[0] - point2[0])**2 + (point1[1] - point2[1])**2

class Solution4(object):
    def numberOfBoomerangs(self, points):
        """
        For the solution mention above, we start from 0 in the second loop, it's not necessary
        we can start from i+1, and update both start_node and end_node with the distance.  In that  case we need create a dict list instead of single dict one by one
        1036 ms, faster than 75.17%
        """
        res, length = 0, len(points)
        dict_list = [{} for _ in range(length)]
        for i in range(length):
            for j in range(i+1, length):
                distance = self.calc_distance(points[i], points[j])
                dict_list[i][distance] = dict_list[i][distance] + 1 if distance in dict_list[i] else 1
                dict_list[j][distance] = dict_list[j][distance] + 1 if distance in dict_list[j] else 1
            for n in dict_list[i]:
                res += dict_list[i][n] * (dict_list[i][n] -1)
        return res
    def calc_distance(self, point1, point2):
        return (point1[0] - point2[0])**2 + (point1[1] - point2[1])**2


class Solution5(object):
    def numberOfBoomerangs(self, points):
        """
        Modify from solution4.
        In solution4 , we count the point[i]' s result after update the dict, it's parallel with updating dict, it will cause time consumption doubled.
        So while updating dict, we can also calc the result.
        For each point's value length n, the result = n*(n-1), so we can use add operation before updating dict every time(1+2+..n-1) and muplitly 2 finally
        804 ms, faster than 91.27% 
        """

        res, length = 0, len(points)
        dict_list = [{} for _ in range(length)]
        for i in range(length):
            for j in range(i + 1, length):
                distance = self.calc_distance(points[i], points[j])
                if distance in dict_list[i]:
                    res += dict_list[i][distance]
                    dict_list[i][distance] +=1
                else:
                    dict_list[i][distance] =1
                if distance in dict_list[j]:
                    res += dict_list[j][distance]
                    dict_list[j][distance] += 1
                else:
                    dict_list[j][distance] =1
        return res*2

    def calc_distance(self, point1, point2):
        return (point1[0] - point2[0])**2 + (point1[1] - point2[1])**2