题目:

给定一个大小为n的数组,找出其中的majority element。majority element是指在数组中出现超过n/2次的元素。

例1:

输入:[3,2,3]

输出:3

例2:

输入:[2,2,1,1,1,2,2]

输出:2

思路:

利用栈来求解。分3种情况:

  1. 栈为空,入栈;
  2. 栈顶元素等于当前元素,入栈;
  3. 否则,出栈。

最后栈中剩下的元素即是所求。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

int majorityElement(int* nums, int numsSize) {
    int* stack = malloc(sizeof(int) * numsSize);    //栈
    int top = -1;   //初始栈为空

    for (int i=0; i<numsSize; i++) {
        if (top == -1) {    //case1
            stack[++top] = nums[i];
        }
        else if (stack[top] == nums[i]) {   //case2
            stack[++top] = nums[i];
        }
        else {      //case3
            top--;
        }
    }
    return stack[0];
}

int main(){
    int nums[] = {1,2,1,2,2,3,2};
    int result = majorityElement(nums, 7);
    printf("The majority element is %d.\n", result);
    return 0;
}

结果:

可以看到效率还是不错的。

算法时间复杂度为O(n),这是必须的,因为要把数组遍历一次。

空间复杂度为O(n),因为构造了与数组等大的栈,最坏的情况是数组全部入栈。

其实这个算法还可以改进,将空间复杂度降到O(1)。

改进思路如下:

其实并不需要真的构造一个栈,只需要一个“虚拟”的栈就可以达到目的。

可以设置一个变量cand表示当前栈中的元素,用另一个变量count表示当前栈中元素的个数,其实就是cand的个数。

3种情况同上:

  1. 栈空,入栈。修改cand,count++;
  2. 栈顶元素等于当前元素,入栈。不用修改cand,count++;
  3. 否则,出栈。count--。

最后cand即是所求。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

int majorityElement(int* nums, int numsSize) {
    int cand, count = 0;
    for (int i=0; i<numsSize; i++) {
        if (count == 0) {    //case1
            cand = nums[i];
            count++;
        }
        else if (cand == nums[i]) {   //case2
            count++;
        }
        else {      //case3
            count--;
        }
    }
    return cand;
}

int main(){
    int nums[] = {1,2,1,2,2,3,2};
    int result = majorityElement(nums, 7);
    printf("The majority element is %d.\n", result);
    return 0;
}

这样,就把空间复杂度降到了O(1)。


参考:【编程练习讲解】一起玩算法01

推荐一位干货up主:正月点灯笼