题目
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
假设数组非空,并且一定存在满足条件的数字。
思考题:
假设要求只能使用 O(n) 的时间和额外 O(1) 的空间,该怎么做呢?
样例
输入:[1,2,1,1,3]
输出:1

解法一:快速选择

长度超过一半,意味着快速选择进行到某一轮之后,左右两部分当中一定有一部分完全一样,我们可以判断最左端或者最右端的数是否和枢轴相等,不是的话,就选择长度超过1/2的那部分继续
时间复杂度O(n),空间复杂度O(1)

  1. class Solution {
  2. public:
  3. int moreThanHalfNum_Solution(vector<int>& nums) {
  4. return quick_select(nums, 0, nums.size() - 1);
  5. }
  6. int quick_select(vector<int> &nums, int l, int r) {
  7. if (l >= r) return nums[l];
  8. int idx = rand() % (r - l + 1) + l;
  9. int x = nums[idx];
  10. int i = l - 1, j = r + 1;
  11. while (i < j) {
  12. while (nums[++i] < x);
  13. while (nums[--j] > x);
  14. if (i < j) swap(nums[i], nums[j]);
  15. }
  16. if (nums[l] == x || nums[r] == x) return x;
  17. int delta = i - l + 1;
  18. if (delta > nums.size() / 2) return quick_select(nums, l, i);
  19. else return quick_select(nums, i + 1, r);
  20. }
  21. };

解法二:众数

出现的次数超过数组长度的一半,也就意味着超过了其余所有数字出现次数的总和
时间复杂度O(n),空间复杂度O(1)

  1. class Solution {
  2. public:
  3. int moreThanHalfNum_Solution(vector<int>& nums) {
  4. int cnt = 0, val = 0;
  5. for (auto x: nums) {
  6. if (x == val) cnt++;
  7. else {
  8. if (cnt) cnt--;
  9. else {
  10. cnt = 1;
  11. val = x;
  12. }
  13. }
  14. }
  15. return val;
  16. }
  17. };