文章目录
- 数组中重复的数字
- 题目
- 思路
- 代码实现
- 中等难度
- 思路
- 代码实现
- 数组中的逆序对
- 题目
- 思路
- 代码实现
- 最小K个数
- 思路
- 代码实现
- 数据流中的中位数
- 题目
- 思路
- 代码实现
数组中重复的数字
题目
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组[2,3,1,0,2,5,3],那么对应的输出是2或者3。存在不合法的输入的话输出-1;
思路
使用HashSet的性质进行判断处理即可;
代码实现
public int duplicate (int[] numbers) {if(numbers == null || numbers.length == 0){return -1;}HashSet<Integer> hashSet = new HashSet<>();for(int num:numbers){if(hashSet.contains(num)){return num;}else{hashSet.add(num);}}return -1;}
中等难度
给你一个长度为 n 的整数数组 nums ,其中 nums 的所有整数都在范围 [1, n] 内,且每个整数出现 一次 或 两次 。请你找出所有出现 两次 的整数,并以数组形式返回。
你必须设计并实现一个时间复杂度为 O(n) 且仅使用常量额外空间的算法解决此问题。
LeetCode链接
思路
由于nums数组中的数字范围为[1-n],则我们可以将对应数字放在其对应下标位置[0~n-1],这样如果存在数字重复,则一定会有num[i]-1!=index存在,这样就可以找出重复数字。
代码实现
public List<Integer> findDuplicates(int[] nums) {List<Integer> result = new ArrayList();for(int i = 0; i < nums.length;i++){while(nums[i] != nums[nums[i]-1]){swap(i,nums[i]-1,nums);}}for(int i = 0; i < nums.length;i++){if(nums[i] - 1 !=i){result.add(nums[i]);}}return result;}private void swap(int i,int j, int[] nums){int temp = nums[i];nums[i] = nums[j];nums[j] = temp;}
数组中的逆序对
题目
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P mod 1000000007
牛客题目链接
思路
采用归并排序思想解决;
代码实现
private int result;/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** * @param nums int整型一维数组 * @return int整型*/public int InversePairs (int[] nums) {if(nums == null || nums.length == 0){return 0;}mergeSort(nums,0,nums.length-1);return result ;}private void mergeSort(int[] nums,int l,int r){int mid = l + (r - l) /2;if(l < r){mergeSort(nums,l,mid);mergeSort(nums,mid+1,r);merge(nums,l,mid,r);}}private void merge(int[] nums,int l,int mid,int r){int[] help = new int[r-l+1];int i = 0;int p1 = l;int p2 = mid +1 ;while(p1 <= mid && p2 <=r){if(nums[p1] <= nums[p2]){help[i++] = nums[p1++];}else {result+=mid - p1+1;result%= 1000000007;help[i++] = nums[p2++];}}while(p1 <= mid){help[i++] = nums[p1++];}while(p2 <= r){help[i++] = nums[p2++];}for(int j =0;j <help.length;j++){nums[l+j] = help[j];}}
最小K个数
设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。
示例:
输入: arr = [1,3,5,7,2,4,6,8], k = 4
输出: [1,2,3,4]
LeetCode链接
思路
- 方法1:
对数组整体进行排序,然后取前k个数;这种方式比较简单,就不再过多赘述,对应时间复杂度为O(nlogn); - 方法2:
- 定义大根堆,Java中对应的就是优先级队列;
- 将数组中前k个数丢入大根堆中;
- 然后遍历[k,arr.length-1]位置数据,每次与大根堆堆顶元素(即队列中最大数)进行比较,如果比最大数小,则堆顶元素出队,新的元素入队,最终会产生新的最小元素,对应时间复杂度为O(nlogk);
代码实现
这里采用大根堆的思路来解决问题;
public int[] smallestK(int[] arr, int k) {if(arr == null || arr.length < k){return new int[0];}if(k == 0){return new int[0];}PriorityQueue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2 - o1;}});int[] result = new int[k];for(int i = 0 ; i< k ; i++){queue.offer(arr[i]);}for(int i = k ; i < arr.length;i++){int peek = queue.peek();if(arr[i] < peek){queue.poll();queue.offer(arr[i]);}}int j = 0;while(!queue.isEmpty()){int num = queue.poll();result[j++] = num;}return result;}
数据流中的中位数
题目
中位数 是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
LeetCode链接
思路
- 定义一个大顶堆和小顶堆;
- 当大顶堆没有元素时,先放入大顶堆中,如果添加的元素小于等于大顶堆堆顶元素,直接放入大顶堆中,否则放入小顶堆中,保证大顶堆中都是较小的一半元素,小顶堆中是较大的一半元素;
- 同时当两个堆中元素数量相差为2时,将元素多的堆顶元素放入元素少的堆中,保证两个堆元素数之差在1以内;
- 此时,取中位数即两种情况:
a. 两个堆中元素数量相等,直接取堆顶元素相加 /2;
b.两个堆中元素数量不相等,则中位数为数量多的堆顶元素;
更多详细思路可参考:Java 贪心算法经典问题解决
代码实现
//Java优先级队列 默认小顶堆private PriorityQueue<Integer> minQueue = new PriorityQueue();// 定义大顶堆private PriorityQueue<Integer> maxQueue = new PriorityQueue<>((x,y) -> (y-x));public MedianFinder() {}//加入元素时public void addNum(int num) {if(maxQueue.size() == 0){maxQueue.offer(num);} else {int peekNum = maxQueue.peek();if(peekNum >= num){maxQueue.offer(num);}else{minQueue.offer(num);}changeQueueSize();}}public double findMedian() {int maxSize = maxQueue.size();if(maxSize == 0){return 0;}int minSize = minQueue.size();if(minSize == maxSize){return (maxQueue.peek() + minQueue.peek()) / 2.0;}double result = maxSize > minSize ? maxQueue.peek(): minQueue.peek();return result;}private void changeQueueSize(){int maxSize = maxQueue.size();int minSize = minQueue.size();if(maxSize - minSize == 2){minQueue.offer(maxQueue.poll());}if(minSize - maxSize == 2){maxQueue.offer(minQueue.poll());}}