数组中超过一半的数字

2019-10-17  本文已影响0人  魏鹏飞

1. 来源

2. 题目描述

题目:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如,输入一个长度为9的数组[1,2,3,2,2,2,5,4,2]。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出是2。

3. 题目分析3种解法

很多应聘者会想到如果是排好序的数组,那么超过数组长度一半的数字肯定是中位数。此时时间复杂度为O(nlogn)。有没有更好的时间复杂度为O(n)的算法呢?

4. 程序实现

  1. Java编码实现
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class Solution {
    // 使用HashMap字典
    public static int moreThanHalfNum(int[] numbers) {
        Map<Integer, Integer> numMap = new HashMap<>();
        for(int num : numbers) {
            if(numMap.containsKey(num)) {
                numMap.put(num, numMap.get(num) + 1);
            } else {
                numMap.put(num, 1);
            }
            // 超过数组长度一半的数字
            if(numMap.get(num) > numbers.length / 2) {
                return num;
            }
        }
        return 0;
    }

    // 基于快排的思想
    public static int quickSelect(int[] numbers, int l, int r, int k) {
        // 递归终止条件
        if(l >= r) {
            return numbers[l];
        }
        int pivot = numbers[r];
        int left = l;
        int right = r - 1;
        while(left <= right) {
            while(left <= right && numbers[left] < pivot) {
                left++;
            }
            while(left <= right && numbers[right] >= pivot) {
                right--;
            }
            if(left > right) {
                break;
            }
            // swap numbers[left] with numbers[right] while left <= right
            int temp = numbers[left];
            numbers[left] = numbers[right];
            numbers[right] = temp;
        }
        // swap the smaller with pivot
        numbers[r] = numbers[left];
        numbers[left] = pivot;

        if(left == k) {
            return numbers[k];
        } else if(left > k) {
            return quickSelect(numbers, l, left - 1, k);
        } else {
            return quickSelect(numbers, left + 1, r, k);
        }

    }

    public static void main(String[] args) {
        int[] numbers = {1, 2, 3, 2, 2, 2, 5, 4, 2};
        System.out.println("方法一-->超过数组长度一半的数字:" + moreThanHalfNum(numbers));
        System.out.println("方法二-->超过数组长度一半的数字:" + quickSelect(numbers, 0, numbers.length - 1, numbers.length / 2));
    }

}

# 结果
方法一-->超过数组长度一半的数字:2
方法二-->超过数组长度一半的数字:2
  1. Python编码实现
class Solution(object):
    
    # 使用字典统计
    def moreThanHalfNum(self, numbers):
        numbers_dict = {}
        for num in numbers:
            if num in numbers_dict:
                numbers_dict[num] += 1
            else:
                numbers_dict[num] = 1
            # 超过一半的数字
            if numbers_dict[num] > len(numbers) // 2:
                return num
        return 0

    # 开枪法(得到的是其中一个整体靠后的众数)
    def moreThanHalfNum2(self, numbers):
        if not numbers:# 空列表
            return 0
        num = numbers[0]
        counter = 1
        for item in numbers:
            if num == item:
                counter += 1
            else:
                counter -= 1
            if counter == 0:
                num = item
                counter = 1
        
        # 判断最后得到的num的个数是否超过数组一半
        counter = 0
        for item in numbers:
            if item == num:
                counter += 1
        return num if counter > len(numbers) //2 else 0

    # 基于快排思想
    def quickSelect(self, numbers, l, r, k):
        if l >= r:
            return
        pivot = numbers[r]
        left, right = l, r - 1
        while left <= right:
            while left <= right and numbers[left] < pivot:
                left += 1
            while left <= right and numbers[right] >= pivot:
                right -= 1
            if left > right:
                break
            # swap numbers[left] with numbers[right] while left <= right
            numbers[left], numbers[right] = numbers[right], numbers[left]

        # swap the smaller with pivot
        numbers[left], numbers[r] = numbers[r], numbers[left]

        if left == k:
            return numbers[k]
        elif left > k:
            return self.quickSelect(numbers, l, left -1, k)
        else:
            return self.quickSelect(numbers, left + 1, r, k)


if __name__ == "__main__":
    numbers = [1, 2, 3, 2, 2, 2, 5, 4, 2]
    solution = Solution()
    print("方法一-->数组中超过一半的数字是:", solution.moreThanHalfNum(numbers))
    print("方法二-->数组中超过一半的数字是:", solution.moreThanHalfNum2(numbers))
    print("方法三-->数组中超过一半的数字是:", solution.quickSelect(numbers, 0, len(numbers) - 1, len(numbers) // 2))

# 结果
方法一-->数组中超过一半的数字是: 2
方法二-->数组中超过一半的数字是: 2
方法三-->数组中超过一半的数字是: 2
  1. C++编码实现
#include <iostream>
#include <map>

class Solution
{
public:
    // 使用HashMap字典
    int moreThanHalfNum(int* numbers, int length) {
        std::map<int, int> numMap;
        for(int i = 0; i < length; i++) {
            if(numMap.count(numbers[i]) != 0) {
                numMap[numbers[i]]++;
            } else {
                numMap[numbers[i]] = 1;
            }
            // 超过数组长度一半的数字
            if(numMap[numbers[i]] > length / 2) {
                return numbers[i];
            }
        }
        return 0;
    }

    // 基于快排的思想
    int quickSelect(int* numbers, int l, int r, int k) {
        // 递归终止条件
        if(l >= r) {
            return numbers[l];
        }
        int pivot = numbers[r];
        int left = l;
        int right = r - 1;
        while(left <= right) {
            while(left <= right && numbers[left] < pivot) {
                left++;
            }
            while(left <= right && numbers[right] >= pivot) {
                right--;
            }
            if(left > right) {
                break;
            }
            // swap numbers[left] with numbers[right] while left <= right
            int temp = numbers[left];
            numbers[left] = numbers[right];
            numbers[right] = temp;
        }
        // swap the smaller with pivot
        numbers[r] = numbers[left];
        numbers[left] = pivot;

        if(left == k) {
            return numbers[k];
        } else if(left > k) {
            return quickSelect(numbers, l, left - 1, k);
        } else {
            return quickSelect(numbers, left + 1, r, k);
        }

    }

};

int main() {
    int numbers[] = {1, 2, 3, 2, 2, 2, 5, 4, 2};
    Solution solution;
    std::cout << "方法一-->超过数组长度一半的数字:" << solution.moreThanHalfNum(numbers, 9) << std::endl;
    std::cout << "方法二-->超过数组长度一半的数字:" << solution.quickSelect(numbers, 0, 8, 4) << std::endl;

    return 0;
}

# 结果
方法一-->超过数组长度一半的数字:2
方法二-->超过数组长度一半的数字:2
  1. Go编码实现
上一篇下一篇

猜你喜欢

热点阅读