LeetCode 169:求众数

所谓求众数,就是求数组中出现次数超过n/2的数。

之前剑指中做过同一道题:https://blog.csdn.net/chengda321/article/details/93139959

学习花花酱的视频讲解,共有5类解法,10种写法。

第一类:基于哈希表的方法

第1种  Hash Table:对应STL容器unordered_map 

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        unordered_map<int, int> count;
        const int n = nums.size();

        for(int &num : nums) {
            if(++count[num]>n/2) return num;
        }
        return -1;
    }
};

第2种  BST:二叉搜索树,在C++ STL容器中对应map

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        map<int, int> count;
        const int n = nums.size();

        for(int &num : nums) {
            if(++count[num]>n/2) return num;
        }
        return -1;
    }
};

另外附上一种简单的BST递归实现

struct node {
   int val;
   node* left;
   node* right;
};

node* createNewNode(int x)
{
    node* nn = new node;
    nn->val = x;
    nn->left  = nullptr;
    nn->right = nullptr;

    return nn;
}

void bstInsert(node* &root, int x)
{
    if(root == nullptr) {
        root = createNewNode(x);
        return;
    }

    if(x < root->val)
    {
        if(root->left == nullptr) {
            root->left = createNewNode(x);
            return;
        } else {
            bstInsert(root->left, x);
        }
    }

    if( x > root->val )
    {
        if(root->right == nullptr) {
            root->right = createNewNode(x);
            return;
        } else {
            bstInsert(root->right, x);
        }
    }
}

int main()
{
     node* root = nullptr;

     int x;
     while(cin >> x) {
         bstInsert(root, x);
     }

     return 0;
}

第二类:基于随机数的方法

方法3   从统计学意义上讲,平均每随机2次就可以得到众数 

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        srand(time(nullptr));
        const int n = nums.size();

        while(true) {
            int index = rand()%n; //随机产生一个索引
            int majority = nums[index]; //假设它就是众数
            int count = 0;
            for(int & num : nums) {
                if(num == majority && ++count>n/2) return num; //此处用到了逻辑与&&的短路特性
            }
        }
        //return -1; 写不写都可,因为这道题假设存在众数
    }
};

第三类:vote-based 

方法4  bit vote  思路:众数的每一个二进制位都是众数

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        const int n = nums.size();
        int majority = 0;

        for(int i=0; i<32; i++) { //32bits
            int mask = 1 << i ; //错把1打成i
            int count = 0;
            for(int& num : nums) {
                if((mask & num) && ++count>n/2) {
                    majority |= mask;
                    break;
                }
            }
        }
        return majority;
    }
};

方法5  Moore vote  不同的数对消,最后留下的一定是众数

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        const int n = nums.size();
        int count = 1;
        int majority = nums[0]; //首先,认为第一个元素就是众数
        for(int i=1; i<n; i++) {
            if(count==0) {
                count = 1;
                majority = nums[i];
            }
            else {
                if(majority == nums[i]) count++;
                else count--;
            }
        }
        return majority;
    }
};

第四类 基于排序的方法

方法6 Full Sort  排序,取中间的数

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        const int n = nums.size();
        std::sort(nums.begin(), nums.end());
        return nums[n/2];
    }
};

方法7 Partial Sort 与快排中的经典的Partial思想一样 (?)

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        const int n = nums.size();
        std::nth_element(nums.begin(), nums.begin()+n/2, nums.end());
        return nums[n/2];
    }
};

方法8  自己实现Partial函数

自己实现的方法,总有测试用例超过时间限制

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int n = nums.size();
        int mid = Partition(nums, 0, n-1);
        while(mid!=n/2) {
            if(mid > n/2)
                mid = Partition(nums, 0, mid-1);
            else
                mid = Partition(nums, mid+1, n-1);
        }
        return nums[mid];
    }
private:
    //经典的Partition函数实现
    int Partition(vector<int>& nums, int left, int right) {
        srand(time(nullptr));
        int index = left + rand() % (right-left+1);

        Swap(nums[index], nums[right]);
        int small = left-1;
        for(int i = left; i<right; ++i) {
            if(nums[i] < nums[right]) {
                ++small; //又增加了一个比 标准数 小的数
                if(small < i) {
                    Swap(nums[small], nums[i]); //出现的第small个比标准数小的,0-small位都应该是比标准数小的数
                }
            }
        }
        Swap(nums[small+1], nums[right]);

        return small+1; //把分界线的index返回 
    }

    void Swap(int& a, int& b) {
        int temp = a;
        a = b;
        b = temp;
    }
};

第五类  分治法

 方法9  不断缩小问题规模,查找左右子集的众数,并返回给上一级

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        const int n = nums.size();
        return majorityElement(nums, 0, n-1);
    }
private:
    int majorityElement(vector<int>& nums, int l, int r) {
        if(l == r) return nums[l]; //分到最后只剩下1个元素
        int mid = l + (r - l)/2;
        int ml = majorityElement(nums, l, mid);
        int mr = majorityElement(nums, mid+1, r);
        if(ml == mr) return ml;
        return count(nums.begin()+l, nums.begin()+r+1, ml) > count(nums.begin()+l, nums.begin()+r+1, mr) ? ml : mr;
    }
};

方法10  左右子集的众数不同时,不需要在全部集合上对两个目标计数来判定哪个为众数。

只需要计数一侧就可以:需要把众数出现的次数作为pair的一部分一起返回。

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        const int n = nums.size();
        return majorityElement(nums, 0, n-1).first;
    }
private:
    pair<int, int> majorityElement(vector<int>& nums, int l, int r) {
        if (l == r) return {nums[l], 1};
        int mid = l + (r-l)/2;
        auto ml = majorityElement(nums, l, mid); 
        auto mr = majorityElement(nums, mid+1, r);

        if(ml.first == mr.first) return {ml.first, ml.second + mr.second}; //等号打成了赋值号,样例运行没错,但后面的会出错
        if(ml.second > mr.second) {
            return {ml.first, ml.second + count(nums.begin()+mid+1, nums.begin()+r+1, ml.first)};
        }
        else {
            return {mr.first, mr.second + count(nums.begin()+l, nums.begin()+mid+1, mr.first)};
        }
    }
};
发布了97 篇原创文章 · 获赞 11 · 访问量 2484

猜你喜欢

转载自blog.csdn.net/chengda321/article/details/102907115