169. Majority Element

Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.

You may assume that the array is non-empty and the majority element always exist in the array.

Example 1:

Input:[3,2,3]

Output:3

Example 2:

Input:[2,2,1,1,1,2,2]

Output:2


① sort the array first and check if the sub-array' length is more than len(nums)//2.

class Solution(object):

    def majorityElement(self, nums):

        """

        :type nums: List[int]

        :rtype: int

        """

        nums.sort()

        for i in range(len(nums)):

            if nums[i]!=nums[i+len(nums)//2]:

                continue

            else:

                return nums[i]

②use set to abstract all the different elements, then use count function to check.

class Solution(object):

    def majorityElement(self, nums):

        """

        :type nums: List[int]

        :rtype: int

        """

        a = set(nums)

        for i in a:

            if nums.count(i) > len(nums)//2:

                return i


Approach 2: HashMap

Intuition

We know that the majority element occurs more than n/2 times, and a HashMap allows us to count element occurrences efficiently.

Algorithm

We can use a HashMap that maps elements to counts in order to count occurrences in linear time by looping over nums. Then, we simply return the key with maximum value.

class Solution(object):

    def majorityElement(self, nums):

        """

        :type nums: List[int]

        :rtype: int

        """

        counts = collections.Counter(nums)

        return max(counts.keys(), key=counts.get) # use 'key=counts.get' to make sure the 'key' is not the original key but the count numbers.

Approach 3: Sorting

Intuition

If the elements are sorted in monotonically increasing (or decreasing) order, the majority element can be found at index n/2  or  n/2 + 1, incidentally, if n is even).

Algorithm

For this algorithm, we simply do exactly what is described: sort nums, and return the element in question. To see why this will always return the majority element (given that the array has one), consider the figure below (the top example is for an odd-length array and the bottom is for an even-length array):

class Solution(object):

    def majorityElement(self, nums):

        """

        :type nums: List[int]

        :rtype: int

        """

        nums.sort()

        return nums[len(nums)//2] # the idea behind is excellent. just imagine the sub-array of majority element will take up most of the space of the original array

Approach 4: Randomization

Intuition

Because more than n/2 array indices are occupied by the majority element, a random array index is likely to contain the majority element.

Algorithm

Because a given index is likely to have the majority element, we can just select a random index, check whether its value is the majority element, return if it is, and repeat if it is not. The algorithm is verifiably correct because we ensure that the randomly chosen value is the majority element before ever returning.

class Solution(object):

    def majorityElement(self, nums):

        """

        :type nums: List[int]

        :rtype: int

        """

        majority_count = len(nums)//2

        while True:

            candidate = random.choice(nums)

            if sum(1 for elem in nums if elem == candidate) > majority_count: # notice how this line is written

                return candidate

Approach 5: Divide and Conquer

Intuition

If we know the majority element in the left and right halves of an array, we can determine which is the global majority element in linear time.

Algorithm

Here, we apply a classical divide & conquer approach that recurses on the left and right halves of an array until an answer can be trivially achieved for a length-1 array. Note that because actually passing copies of subarrays costs time and space, we instead pass lo and hi indices that describe the relevant slice of the overall array. In this case, the majority element for a length-1 slice is trivially its only element, so the recursion stops there. If the current slice is longer than length-1, we must combine the answers for the slice's left and right halves. If they agree on the majority element, then the majority element for the overall slice is obviously the same[1]. If they disagree, only one of them can be "right", so we need to count the occurrences of the left and right majority elements to determine which subslice's answer is globally correct. The overall answer for the array is thus the majority element between indices 0 and nn.

class Solution:

    def majorityElement(self, nums, lo=0, hi=None): 

        def majority_element_rec(lo, hi):

            # base case; the only element in an array of size 1 is the majority

            # element.

            if lo == hi:

                return nums[lo]

            # recurse on left and right halves of this slice.

            mid = (hi-lo)//2 + lo

            left = majority_element_rec(lo, mid)

            right = majority_element_rec(mid+1, hi)

            # if the two halves agree on the majority element, return it.

            if left == right:

                return left

            # otherwise, count each element and return the "winner".

            left_count = sum(1 for i in range(lo, hi+1) if nums[i] == left)

            right_count = sum(1 for i in range(lo, hi+1) if nums[i] == right)

            return left if left_count > right_count else right

        return majority_element_rec(0, len(nums)-1)

Approach 6: Boyer-Moore Voting Algorithm

Intuition

If we had some way of counting instances of the majority element as +1+1 and instances of any other element as -1−1, summing them would make it obvious that the majority element is indeed the majority element.

Algorithm

Essentially, what Boyer-Moore does is look for a suffix suf of nums where suf[0] is the majority element in that suffix. To do this, we maintain a count, which is incremented whenever we see an instance of our current candidate for majority element and decremented whenever we see anything else. Whenever count equals 0, we effectively forget about everything in nums up to the current index and consider the current number as the candidate for majority element. It is not immediately obvious why we can get away with forgetting prefixes of nums - consider the following examples (pipes are inserted to separate runs of nonzero count).

[7, 7, 5, 7, 5, 1 | 5, 7 | 5, 5, 7, 7 | 7, 7, 7, 7]

Here, the 7 at index 0 is selected to be the first candidate for majority element. count will eventually reach 0 after index 5 is processed, so the 5 at index 6 will be the next candidate. In this case, 7 is the true majority element, so by disregarding this prefix, we are ignoring an equal number of majority and minority elements - therefore, 7 will still be the majority element in the suffix formed by throwing away the first prefix.

[7, 7, 5, 7, 5, 1 | 5, 7 | 5, 5, 7, 7 | 5, 5, 5, 5]

Now, the majority element is 5 (we changed the last run of the array from 7s to 5s), but our first candidate is still 7. In this case, our candidate is not the true majority element, but we still cannot discard more majority elements than minority elements (this would imply that countcould reach -1 before we reassign candidate, which is obviously false).

Therefore, given that it is impossible (in both cases) to discard more majority elements than minority elements, we are safe in discarding the prefix and attempting to recursively solve the majority element problem for the suffix. Eventually, a suffix will be found for which count does not hit 0, and the majority element of that suffix will necessarily be the same as the majority element of the overall array.

class Solution:

    def majorityElement(self, nums):

        count = 0 #if it goes back to 0 again, the former sub-array doesn't have majority elements. so we can then give up this sub-array and find the majority elements in the rest of the array.  the logic behind is soooooo brilliant.

        candidate = None

        for num in nums:

            if count == 0:

                candidate = num

            count += (1 if num == candidate else -1)

        return candidate


the use of collections.Counter() and max(counts.keys(), key=counts.get)

approach 3 idea

approach 4 idea

approach 5 idea: exception, recurse, two cases.

approach 6 idea: Boyer-Moore Voting Algorithm

你可能感兴趣的:(169. Majority Element)