LeetCode169求眾數——分治

Pi_dan發表於2018-03-04


題目:

給定一個大小為 n 的陣列,找到其中的眾數。眾數是指在陣列中出現次數大於 ⌊ n/2 ⌋ 的元素。

你可以假設陣列是非空的,並且陣列中的眾數永遠存在。

方法:

  • Hash Table
將每個數字彷彿雜湊表中,記數,直到某個數的count>n/2。時間複雜度為o(n)。
  • 排序
因為眾數是出現次數大於n/2的數字,所以排序之後中間的那個數字一定是眾數。即nums[n/2]為眾數。時間複雜度即排序的時間複雜度。
  • 分治法

分治法是將整個問題化簡為一個一個的小問題去解,將陣列分成簡單的幾部分,比如講一組數分為兩部分,第一部分的眾數如果等於第二部分的眾數,則這個數就是上一層那一組的眾數,如果第一部分不等於第二部分,則遍歷這一組數,記錄這兩個數的出現頻率,返回為頻率最大的,如果頻率相同,返回誰都無所謂,因為在這裡眾數x肯定存在的,那麼肯定會有至少兩個x相連,如果不相連的話,那最後一個數字肯定是眾數x。(例如:1 2 1 2 1 2 1,12112)。時間複雜度為o(n)。

我用了分治法解決的,下面是測試程式碼:

public class LC169 {

    static int[] nums = {1,2,1,3,1,2,1};


    public static void main(String[] args) {

        int result = find(nums,0,nums.length-1);
        System.out.println(result);

    }

    public static int find(int[] nums, int begin, int end){
        if (begin == end)
            return nums[begin];
        else {
            int mid = (begin+end)/2;
            int left = find(nums,begin,mid);
            int right = find(nums,mid+1,end);

            if(left == right)//左右兩部分的眾數相同 則這個數是這部分的眾數
                return left;
            else{//左右兩部分的眾數不相同 則這兩個數都有可能是這部分的眾數
                //那麼遍歷這個陣列 看一下哪個數字的出現頻率高
                int countLeft = 0;
                int countRight = 0;

                for (int i = begin; i <= end; i++)
                    if(nums[i] == left)
                        countLeft++;
                    else if (nums[i] == right)
                        countRight++;

                if(countLeft>=countRight)
                    return left;
                else
                    return right;
            }
        }
    }

}

下面是提交程式碼

class Solution {
    public int majorityElement(int[] nums) {
        return find(nums,0,nums.length-1);        
    }
    
        public static int find(int[] nums, int begin, int end){
        if (begin == end)
            return nums[begin];
        else {
            int mid = (begin+end)/2;
            int left = find(nums,begin,mid);
            int right = find(nums,mid+1,end);

            if(left == right)//左右兩部分的眾數相同 則這個數是這部分的眾數
                return left;
            else{//左右兩部分的眾數不相同 則這兩個數都有可能是這部分的眾數
                //那麼遍歷這個陣列 看一下哪個數字的出現頻率高
                int countLeft = 0;
                int countRight = 0;
                for (int i = begin; i <= end; i++)
                    if(nums[i] == left)
                        countLeft++;
                    else if (nums[i] == right)
                        countRight++;

                if(countLeft>countRight)
                    return left;
                else
                    return right;
            }
        }
    }

    
}

  • Moore voting alogrithm

每次從陣列中找出一對不同的元素,將它們從陣列中刪除,直到遍歷完整個陣列。由於這道題已經說明一定存在一個出現次數超過一半的元素,所以遍歷完陣列後陣列中一定會存在至少一個元素。

相關文章