题目0:
给定一个数组,求如果排序之后,相邻两数的最大差值,要求时间复杂度0(N),且要求不能用非基于比较的排序。(常考)
思路:借用桶的概念,
第一步,准备桶,如果数组中有n个数,我们就准备N+1个桶,遍历整个数组找到最小值和最大值,如果最小值和最大值相等,说明差值为0,如果不等,最小值放在0号桶,最大值放到N号桶,将最小值到最大值的范围里将桶分为N+1份 ,举例:
数组有9个数,最大值99,最小值0,准备10个桶,所以分为09,1019,…7989,9099这10个范围,中间的数属于哪个范围就放哪个桶
将数都放完后必有一个空桶,并且,在每个桶中,只记录最大值和最小值,还有此桶是否进过数,用Boolean记录,最后计算最大值
代码:
/**
* @author :LY
* @date :Created in 2021/3/12 19:46
* @modified By:
*/
public class 相邻数差值问题 {
public static int maxGap(int[] nums){
if (nums == null || nums.length < 2){
return 0;
}
int len = nums.length;
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int i = 0; i < len; i++) {
//获取数组最大值和最小值
min = Math.min(min,nums[i]);
max = Math.max(max,nums[i]);
}
if (min == max){
return 0;
}
boolean[] hasNum = new boolean[len+1];
int[] maxs = new int[len + 1];
int[] mins = new int[len + 1];
int bid = 0;
for (int i = 0; i < len; i++) {
//计算当前数属于几号桶
bid = bucket(nums[i],len,min,max);
mins[bid] = hasNum[bid] ? Math.min(mins[bid],nums[i]):nums[i];
mins[bid] = hasNum[bid] ? Math.max(mins[bid],nums[i]):nums[i];
hasNum[bid] = true;
}
int res = 0;
int lastMax = maxs[0];
int i = 1;
for (; i <= len ; i++) {
if (hasNum[i]){
res = Math.max(res,mins[i] - lastMax);
lastMax = maxs[i];
}
}
return res;
}
public static int bucket(long num,long len,long min,long max){0-99 10
return (int) ((num-min)*len/(max-min));
}
}
题目一:
用数组结构实现大小固定的队列和栈
static class ArrayQueue{
private Integer[] arr;
private Integer size;
private Integer start;
private Integer end;
public ArrayQueue(int initSize){
if (initSize < 0){
throw new IllegalArgumentException("不能为0");
}
arr = new Integer[initSize];
size = 0;
start = 0;
end = 0;
}
public Integer peek(){
if (size == 0){
return null;
}
return arr[start];
}
public void push(int obj){
if (size == arr.length){
throw new ArrayIndexOutOfBoundsException("队列已满");
}
size++;
arr[end] = obj;
end = end==arr.length -1 ? 0 :end+1;
}
public Integer poll(){
if (size == 0){
throw new ArrayIndexOutOfBoundsException("队列空");
}
size -- ;
int tmp = start;
start = start == arr.length -1 ? 0:start +1;
return arr[tmp];
}
}
题目二:
实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中最小元素的操作。
要求:
1.pop、push、getMin操作时间复杂度都是O(1).
2.设计的栈类型可以使用现成的栈结构
设计思路 准备两个栈 Data栈与min栈
设计思路:data栈压入一个数,min栈同时压入一个数,后续的数依次与min栈栈顶进行比较,压入较小的数,大小相同则再压min栈栈顶,data弹出数min栈也弹出数
题目三:
如何仅用队列结构实现栈结构?
思路:建立两个队列,每次返回一个数就留下最后一个数返回
public class 队列实现栈 {
static class TwoQueuesStack{
private Queue<Integer> queue;
private Queue<Integer> help;
public TwoQueuesStack(){
queue = new LinkedList<>();
help = new LinkedList<>();
}
public void push(int pushInt){
queue.add(pushInt);
}
public int peek(){
if (queue.isEmpty()){
throw new RuntimeException("Stack is empty");
}
while (queue.size()!=1){
help.add(queue.poll());
}
int res = queue.poll();
help.add(res);
swap();
return res;
}
public int pop(){
if (queue.isEmpty()){
throw new RuntimeException("Stack is empty");
}
while (queue.size()>1){
help.add(queue.poll());
}
int res = queue.poll();
swap();
return res;
}
private void swap(){
Queue<Integer> tmp = help;
help = queue;
queue = tmp;
}
}
}
如何仅用栈结构实现队列结构?
和上面题目思路相同
需要满足两个行为,一、倒数要倒完 二、被倒的栈不能有数
题目四
使用两个队列分别存放猫狗,每进来一个就打上时间戳再放入相应的队列中
/**
* @author :LY
* @date :Created in 2021/3/14 15:29
* @modified By:
*/
public class 猫狗队列 {
public static class Pet{
private String type;
public Pet(String type){
this.type = type;
}
public String getPetType(){
return this.type;
}
}
public static class Dog extends Pet{
private String type;
public Dog(String type){
super("dog");
}
}
public static class Cat extends Pet{
private String type;
public Cat(String type){
super("cat");
}
}
public static class PetEnter{
private Pet pet;
private long count;
public PetEnter(Pet pet,long count){
this.pet = pet;
this.count = count;
}
public Pet getPet(){
return this.pet;
}
public long getCount(){
return this.count;
}
public String getEnterPetType(){
return this.pet.getPetType();
}
}
public static class DogCatQueue{
private Queue<PetEnter> dogQ;
private Queue<PetEnter> catQ;
private long count;
public DogCatQueue(){
this.dogQ = new LinkedList<>();
this.catQ = new LinkedList<>();
this.count = 0;
}
public void add(Pet pet){
if (pet.getPetType().equals("dog")){
this.dogQ.add(new PetEnter(pet,this.count++));
}else if (pet.getPetType().equals("cat")){
this.catQ.add(new PetEnter(pet,this.count++));
}else {
throw new RuntimeException("err,not dog or cat");
}
}
public Pet pollAll(){
if (!this.dogQ.isEmpty() && !this.catQ.isEmpty()){
if (this.dogQ.peek().getCount() < this.catQ.peek().getCount()){
return this.dogQ.poll().getPet();
}else {
return this.catQ.poll().getPet();
}
}else if (!this.dogQ.isEmpty()){
return this.dogQ.poll().getPet();
}else if (!this.catQ.isEmpty()){
return this.catQ.poll().getPet();
}else {
throw new RuntimeException("err,queue is empty");
}
}
public Dog pollDog(){
if (!this.dogQ.isEmpty()){
return (Dog) this.dogQ.poll().getPet();
}else {
throw new RuntimeException("err,dogqueue is empty");
}
}
public Cat pollCat(){
if (!this.catQ.isEmpty()){
return (Cat) this.catQ.poll().getPet();
}else {
throw new RuntimeException("err,catqueue is empty");
}
}
public boolean isEmpty(){
return this.dogQ.isEmpty()&&this.catQ.isEmpty();
}
public boolean isDogEmpty(){
return this.dogQ.isEmpty();
}
public boolean isCatEmpty(){
return this.catQ.isEmpty();
}
}
}
题目五:
转圈打印矩阵
给定一个整型矩阵matrix,请按照转圈方式打印它。例如:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
打印结果为: 要求额外空间复杂度为O(1)
1 2 3 4 8 12 16 15 14 13 9 5 6 7 11 10
public static void spiralOrderPrint(int[][] matrix){
int tR = 0;
int tC = 0;
int dR = matrix.length - 1;
int dC = matrix[0].length - 1 ;
while (tR <= dR && tC <= dC){
printEdge(matrix,tR++,tC++,dR--,dC--);
}
}
/**
*
* @param m
* @param tR 左上角的行
* @param tC 左上角的列
* @param dR 右下角的行
* @param dC 右下角的列
*/
public static void printEdge(int[][] m,int tR,int tC,int dR,int dC){
if (tR == dR){
for (int i = tC; i <= dC ; i++) {
System.out.println(m[tR][i] + " ");
}
}else if (tC == dC){
for (int i = tR; i <= dR ; i++) {
System.out.println(m[i][tC] + " ");
}
}else {
int curC = tC;
int curR = tR;
while (curC != dC){
System.out.println(m[tR][curC] + " ");
curC++;
}
while (curR != dR){
System.out.println(m[curR][dC] + " ");
curR++;
while (curC != tC){
System.out.println(m[dR][curC] + " ");
curC--;
}
while (curR != tR){
System.out.println(m[curR][tC] + " ");
curR--;
}
}
}
}
题目六
"之"字形打印矩阵
给定一个矩阵matrix,按照"之"字形的方式打印这个矩阵,例如:
1 2 3 4
5 6 7 8
9 10 11 12
核心是写一个打对角线的函数
/**
* 打印之字形数组
* @author :LY
* @date :Created in 2021/3/16 10:43
* @modified By:
*/
public class 之字形打印数组 {
public static void main(String[] args) {
int[][] arr = new int[3][3];
arr[0][0]=1;
arr[0][1]=2;
arr[0][2]=3;
arr[1][0]=5;
arr[1][1]=6;
arr[1][2]=7;
arr[2][0]=9;
arr[2][1]=10;
arr[2][2]=11;
printMatrixZigZag(arr);
}
public static void printMatrixZigZag(int[][] matrix){
int tR = 0;//左上角的行
int tC = 0;//左上角的列
int dR = 0;//右下角的行
int dC = 0;//右下角的列
int endR = matrix.length -1;
int endC = matrix[0].length - 1;
boolean fromUp = false;
while(tR != endR + 1){
printLevel(matrix,tR,tC,dR,dC,fromUp);
tR = tC == endC ? tR + 1: tR;
tC = tC == endC ? tC : tC + 1;
dC = dR == endR ? dC + 1 : dC;
dR = dR == endR ? dR : dR + 1;
fromUp = !fromUp;
}
}
public static void printLevel(int[][] m,int tR,int tC,int dR,int dC,boolean f){
if (f){
while (tR != dR+1){
System.out.println(m[tR++][tC--] + " ");
}
}else {
while (dR != tR - 1){
System.out.println(m[dR--][dC++] + " ");
}
}
}
}
题目7
在行列都排好序的矩阵中找数
给定一个有N*M的整型矩阵matrix和一个整数K,matrix的每一行和每一列都是排好序的。实现一个函数,判断K是否在matrix中。例如:
0 1 2
1 2 3
6 7 8
如果k为7,返回true,如果k为6,返回false。 要求时间复杂度为0(N+M),额外空间复杂度为O(1)。
思路分析:假设需要找4,从右上角开始找,如果比4大,直接将当前整列排除(因为是排好序的),往左移,继续刚才的操作
public class 矩阵找数 {
public static void main(String[] args) {
int[][] arr = new int[3][4];
arr[0][0]=1;
arr[0][1]=3;
arr[0][2]=5;
arr[0][3]=6;
arr[1][0]=2;
arr[1][1]=5;
arr[1][2]=7;
arr[1][3]=9;
arr[2][0]=4;
arr[2][1]=6;
arr[2][2]=8;
arr[2][3]=10;
printHit(arr,8);
}
public static void printHit(int[][] arr,int num){
//拿到右上角的坐标
int tR = 0;
int tC = arr[0].length-1;
int dR = arr.length-1;
int dC = -1;
while (tR != dR || tC != dC){
if (arr[tR][tC] == num){
System.out.println("已找到");
break;
}
// if (arr[tR][tC] > num){
// tC--;
//
// }else {
// tR ++;
//
// }
tC = arr[tR][tC] > num?tC-1:tC;
tR = arr[tR][tC] < num?tR+1:tR;
}
}
}