这是我参与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 <= 100000 <= 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)