剑指Offer 39 40

139 阅读1分钟

这是我参与8月更文挑战的第19天,活动详情查看:8月更文挑战

剑指 Offer 39. 数组中出现次数超过一半的数字

题目

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2

限制:

  • 1 <= 数组长度 <= 50000

方法一

投票算法:最后的胜者一定超过一半的票,因此可以维护一个当前胜出者res和其当前的票数cnt,如果枚举到的投票人投的票不是当前胜者,那么他的票数-1;如果投的是当前胜者,则+1;当票数为0时,换人;

class Solution {
    public int majorityElement(int[] nums) {
        int res = 0, cnt = 0;
        for (int x : nums) {
            if (cnt == 0) {
                res = x;
                cnt ++;
            }else if (x == res) {
                cnt ++;
            }else
                cnt --;
        }
        return res;
    }
}

时间复杂度: O(n)

空间复杂度: O(1)

剑指 Offer 40. 最小的k个数

题目

输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

示例 1:

输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]

示例 2:

输入:arr = [0,1,2,1], k = 1
输出:[0]

限制:

  • 0 <= k <= arr.length <= 10000
  • 0 <= arr[i] <= 10000

方法一

快速选择:利用快排,每次确定一个元素的最终位置index,若该位置等于k,则说明k之前的已经是数组中最小的一批元素,直接返回;若大于k,从左边界到index-1继续分;若小于k,从index+1到有边界继续分;

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        if (k > arr.length) return arr;
        quick_sort(arr, k, 0, arr.length - 1);
        int[] res = new int[k];
        for (int i = 0; i < k; i ++ )
            res[i] = arr[i];
        return res;
    }
    void quick_sort(int[] arr, int k, int l, int r) {
        if (l >= r) return;
        int i = l, j = r, x = arr[l];
        while(i < j) {
            while(arr[j] >= x && i < j) j --;
            while(arr[i] <= x && i < j) i ++;
            swap(arr, i, j);
        }
        swap(arr, l, j);
​
        if (j > k) quick_sort(arr, k, l, j - 1);
        else if (j < k) quick_sort(arr, k, j + 1, r);
        return ;
    }
    void swap(int[] arr, int x, int y) {
        int t = arr[x];
        arr[x] = arr[y];
        arr[y] = t;
    }
}

时间复杂度: O(n),每轮是n/2,总的就是n/2 + n/4 + ... + n/n = 2n - 1

空间复杂度: O(logn)