这是我参与11月更文挑战的第22天,活动详情查看:2021最后一次更文挑战
我是小黑,一个在互联网“苟且”的程序员。
流水不争先,贵在滔滔不绝
本期内容是对上一期【算法系列】Array算法题详细解析的一个延伸,主要包含三道数组相关算法题目的解题思路和代码实现。
将数组中的奇数和偶数分开
题目描述:
给定一个整数数组,将数组中的奇数和偶数分开。元素的顺序可以改变。
思路:
- 假设数组是arr[]
- 初始化两个索引变量,left=0,right=arr.length-1
- 递增left变量知道数值为奇数
- 递减right变量直到数值为偶数
- 如果left<right,将arr[left]和arr[right]交换
- 最后的结果左边是偶数,右边是奇数
代码实现:
package com.heiz.algorithm.array;
/**
* @author 小黑说Java
* @ClassName SeparateOddEvenMain
* @Description
* @date 2021/11/21
**/
public class SeparateOddEvenMain {
public static void main(String[] args) {
int[] arr = {12, 17, 70, 15, 22, 65, 21, 90};
System.out.println("原始数组: ");
for (int j : arr) {
System.out.print(j + " ");
}
separateEvenOddNumbers(arr);
System.out.println("\n奇数和偶数分开后数组: ");
for (int j : arr) {
System.out.print(j + " ");
}
}
public static void separateEvenOddNumbers(int[] arr) {
int left = 0;
int right = arr.length - 1;
for (int i = 0; i < arr.length; i++) {
while (arr[left] % 2 == 0) {
left++;
}
while (arr[right] % 2 == 1) {
right--;
}
if (left < right) {
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
}
}
}
}
复制代码
运行结果:
对一个只有012的数组用O(n)时间复杂度排序
题目描述:

现有整数数组,其内部元素只有0,1,2,例如:int[] arr = [1, 2, 2, 0, 0, 1, 2, 2, 1]
,对其进行排序,要求为O(1)时间复杂度。
思路:
因为数组中只有数字012,所以先遍历一遍数组,记录下0,1,2出现的次数,然后重新遍历一遍数组,按照012出现的次数重新对数组中的元素赋值。
步骤:
-
遍历给定数组一次,并不断增加所遇到的数字的计数。
-
再次遍历数组,从索引0开始,不断改变当前索引上元素的值,首先耗尽所有的0,然后是1,最后是所有的2
这种方式必须对数组遍历两次,第一次为统计出现次数,第二次重新赋值,时间复杂度为O(n)。
代码实现:
package com.heiz.algorithm.array;
/**
* @author 小黑说Java
* @ClassName Sort012
* @Description
* @date 2021/11/21
**/
public class Sort012 {
public static void main(String[] args) {
int[] a = {1, 0, 2, 0, 0, 1, 2, 2, 1};
sort(a);
for (int val : a) {
System.out.print(val + " ");
}
}
public static void sort(int[] a) {
// 保存0,1,2出现的次数
int[] freq = new int[3];
for (int val : a) {
freq[val]++;
}
int pointer = 0;
for (int i = 0; i < freq.length; i++) {
while (freq[i]-- > 0) {
a[pointer] = i;
pointer++;
}
}
}
}
复制代码
查找滑动窗口最大值
题目描述:
给定一个整数数组和一个整数k,从所有大小为k的连续子数组中找出最大元素。
比如:
Input : int[] arr = {2,6,-1,2,4,1,-6,5}
int k = 3
复制代码
则对应的输出结果应该是:
output : 6,6,4,4,4,5
复制代码
也就是对每一个大小为3的子数组,打印其中的最大值。
思路:
将数组按照K生成所有的子数组,然后遍历找出他们的最大值。
这种方式对于每个点基本都是取下一个K个元素,然后遍历,找到最大值,这个算法的时间复杂度为O(n*k)。
代码实现:
package com.heiz.algorithm.array;
/**
* @author 小黑说Java
* @ClassName SlidingWindowMax
* @Description
* @date 2021/11/21
**/
import java.util.Scanner;
public class SlidingWindowMax {
public static void main(String[] args) {
System.out.println("请输入数组大小:");
Scanner scn = new Scanner(System.in);
int[] arr = new int[scn.nextInt()];
System.out.println("请输入数组元素:");
for (int i = 0; i < arr.length; i++) {
arr[i] = scn.nextInt();
}
System.out.println("请输入窗口大小:");
int windowSize = scn.nextInt();
solve(arr, windowSize);
}
public static void solve(int[] arr, int k) {
for (int i = k; i <= arr.length; i++) {
int max = Integer.MIN_VALUE;
for (int j = i - k; j < i; j++) {
max = Math.max(max, arr[j]);
}
System.out.print(max +"\t");
}
}
}
复制代码
运行结果:
思路二:
使用Deque来帮助我们找到O(n)中滑动窗口的最大值。
Deque是一个双端队列,也就是说,你可以从前面或后面添加或删除元素。
我们解决这个问题的方法是:
我们保留子数组的k个元素以相反的顺序,我们不需要保留所有的k个元素,我们将在后面的代码中看到。
为前k个元素生成Deque,保持它们的倒序,以便最大的元素在前面。
如果Deque是空的,直接添加元素,否则检查传入的元素是否大于最后一个元素,如果是,继续从最后一个元素弹出元素,直到剩余Deque的最后一个元素大于传入的元素。
我们还需要删除属于不同子数组的元素。即Deque的下标必须在[i, i+k]范围内。
代码实现:
package com.heiz.algorithm.array;
import java.util.LinkedList;
import java.util.Scanner;
/**
* @author 小黑说Java
* @ClassName SlidingWindowMax
* @Description
* @date 2021/11/21
**/
public class SlidingWindowMax {
public static void main(String[] args) {
System.out.println("请输入数组大小:");
Scanner scn = new Scanner(System.in);
int[] arr = new int[scn.nextInt()];
System.out.println("请输入数组元素:");
for (int i = 0; i < arr.length; i++) {
arr[i] = scn.nextInt();
}
System.out.print("arr[]: {");
for (int j : arr) {
System.out.print(" " + j);
}
System.out.println(" }");
System.out.println("请输入窗口大小:");
int windowSize = scn.nextInt();
solveEfficient(arr, windowSize);
}
public static void solveEfficient(int[] arr, int k) {
LinkedList<Integer> deque = new LinkedList<>();
for (int i = 0; i < arr.length; i++) {
while (!deque.isEmpty() && arr[deque.getLast()] <= arr[i]) {
deque.removeLast();
}
while (!deque.isEmpty() && deque.getFirst() <= i - k) {
deque.removeFirst();
}
deque.addLast(i);
if (i >= k - 1) {
System.out.print(" " + arr[deque.getFirst()]);
}
}
}
}
复制代码
运行结果: