算法练习day7——190325(比较器、不基于比较的排序、maxGap、数组实现栈和队列、minStack)

1.比较器

1.1 Arrays.sort()

Arrays.sort(数组)

  • 若其中的数组元素时自定义类型,报错;
  • 若为基本类型,则按值排序。

Arrays.sort(数组,自己定义的比较器):

  • 会按定义的比较器进行比较排序。

1.2 比较器

是一个自己定义的类。

类名 implements Comparator

实现其中的public int compare(Student o1,Student o2)方法:

  • 此方法返回一个负数:说明o1更小,即o1应该排在前面;
  • 返回一个正数:第二个应该放在前面;
  • 返回0:两个一样大

C++中重载运算符就是自己定义比较器的一种方式。

package Comparator;import java.util.Arrays;
import java.util.Comparator;class Student{int id;String name;int age;public Student(int id,String name,int age) {this.id=id;this.name=name;this.age=age;}
}
public class ComparatorTest {public static void main(String[] args) {Student[] students=new Student[3];students[0]=new Student(3,"llll",23);students[1]=new Student(2,"ssss",18);students[2]=new Student(1,"qqqq",34);//Arrays.sort(students);//printArray(students);Arrays.sort(students,new IdAscendingComparator());printArray(students);Arrays.sort(students,new IdDscendingComparator());printArray(students);Arrays.sort(students,new AgeAscendingComparator());printArray(students);Arrays.sort(students,new AgeDscendingComparator());printArray(students);}public static void printArray(Student[] arr) {for(int i=0;i{@Overridepublic int compare(Student arg0, Student arg1) {/** if(arg0arg1)* return 正数;* else* return 0;*/return arg0.id-arg1.id;}	
}class IdDscendingComparator implements Comparator{@Overridepublic int compare(Student arg0, Student arg1) {return arg1.id-arg0.id;}	
}class AgeAscendingComparator implements Comparator{@Overridepublic int compare(Student arg0, Student arg1) {return arg0.age-arg1.age;}	
}class AgeDscendingComparator implements Comparator{@Overridepublic int compare(Student arg0, Student arg1) {return arg1.age-arg0.age;}	
}

运行结果:

1.3 PriorityQueue

堆结构也可用比较器

优先级队列就是堆。

若没有给比较器,则报错。

package Comparator;import java.util.PriorityQueue;public class PriorityQueueTest {public static void main(String[] args) {Student student1=new Student(3,"llll",23);Student student2=new Student(2,"ssss",18);Student student3=new Student(1,"qqqq",34);PriorityQueue heap=new PriorityQueue<>(new AgeDscendingComparator());//按age大的放在头部heap.add(student1);heap.add(student2);heap.add(student3);while(!heap.isEmpty()) {Student stu=heap.poll();//弹出堆顶元素,堆大小-1;System.out.println(stu.id+"--"+stu.name+"--"+stu.age);}}
}

运行结果:

1.4 TreeMap

红黑树结构。

系统提供的一个有序的结构,都会伴随着一个比较器的构造。这个比较器告诉这个结构怎么组织。

——基于比较的排序是重点。

2.不基于比较的排序

时间复杂度:O(N)

  • 遍历数组的时间

额外空间复杂度:O(N)

都是稳定的。

与被排序的样本的实际数据状况很有关系, 所以实际中并不经常使用。

计数排序就是桶排序的一个具体体现。

3.给定一个数组, 求如果排序之后, 相邻两数的最大差值, 要求时间复杂度O(N), 且要求不能用非基于比较的排序。

3.1 举例:

原始数据:

排序之后:

所以应该返回3.

3.2 实现方式

借用了桶的概念,但是未用桶排序。

  1. N个数据,准备N+1个桶;用一个全局变量记录最大差值。
  2. 遍历数组,找到min和max
    1. 若min=max,整个数组只有一种数,返回0;
    2. 若不等,min放入桶0,max放入桶N
      1. 将min~max均分成N份,对应N+1个桶,如下图:
      2. 其他数属于哪个范围,放入对应的桶。
  3. 每个桶设置三个属性:
    1. min
    2. max
    3. flag(boolean):表示这个桶是否有元素进入过
      1. 若x进入桶m时,flag=false,则令flag=true,min=max=x;
      2. 若y进入桶m时,flag=true,则只更新min和max
  4. 遍历完后,找每个桶的flag
    1. 若为false,直接跳下一个;
    2. 若为true,找到此桶的前一个非空桶,此桶的min-前非空桶的max得到这两个桶的差值。
    3. 更新最大差值。

3.3 最大差值肯定跨桶的原因分析

如上图,排序后,相临的两个数可能来自同一个桶(11,15),也可能来自不同的桶(15,21)。

N个数,N+1个桶,根据鸽舍原理,肯定存在一个空桶

存在空桶,就可以说明:最大差值一定不来自相同的桶。

因为:

空桶左肯定存在离它最近的非空桶,空桶右边也肯定存在离它最近的布控的桶(最起码桶0和桶N都非空)。

左.max-右.min>桶表示的范围;

一个桶内部的两个元素的差值<桶表示的范围

所以最大差值不会是同一桶中的两个元素——只用关心不同桶的元素。

为什么不直接找非空桶,得到最大差值=左.max-右.min?

如上图,最大差值为19,是相邻两桶产生的差值。

有空桶,只是说明最大差值肯定不是在同一桶中,但不是说最大差值一定来自空桶两侧非空桶的差值。

3.4 代码实现

package Solution;public class MaxGap {public static void main(String[] args) {int[] array= {3,1,6,2,7};System.out.println("maxGap="+maxGap(array));}public static int maxGap(int[] arr) {		int result=0;if (arr == null || arr.length < 2) {return result;}int min=Integer.MAX_VALUE;int max=Integer.MIN_VALUE;int n=arr.length;for(int i=0;iarr[i]?max:arr[i];min=min

运行结果:

3.4.1 结果分析

元素\left \{ 3,1,6,2,7 \right \},其中最大值为7,最小值为1。

5个元素,需要6个桶。

首先,将max-min=7-1=6进行5等分,6/5=1.2,得每段距离长1.2。

然后进行每个元素属于的桶号的计算:

  • 3:(3-1)/1.2=2/1.2=1(取整);
  • 6:(6-1)/1.2=5/1.2=4;
  • 2:(2-1)/1.2=1/1.2=0;

所以分桶结果如下图:

所以result=3;

3.4.2 对于计算桶号的公式的分析

\mathrm{int\: \: index}=(\mathrm{int})((arr[i]-min)*n/(max-min));

即就是:\mathrm{int\: \: index}=(\mathrm{int})\frac{arr[i]-min}{\frac{max-min}{n}}

先算出每段距离的长度(\frac{max-min}{n}),再求出当前元素据起点min的距离(arr[i]-min),最后用后者除以前者就得到当前元素所属于的桶号(index)。

4.用数组结构实现大小固定的栈和队列

4.1 实现栈

4.1.1 分析

index:表示新进来的数应该放置的位置。

一个数入栈时,若index+1>size,则报错;否则这个数放在array[index]的位置,然后index++;

一个数出栈时,若index-1<0,则报错;否则弹出放在array[index-1]位置上的数,然后index--。

4.1.2 代码实现

package Solution;class ArrayStack{Integer[] array;Integer size;	public ArrayStack(int initsize) {if(initsize<0)throw new IllegalArgumentException("The init size is less than 0");elsearray=new Integer[initsize];size=0;}public void push(int num) {if(size==array.length)throw new ArrayIndexOutOfBoundsException("The queue is full");elsearray[size++]=num;}public Integer peek() {if(size==0)throw new ArrayIndexOutOfBoundsException("The queue is empty");elsereturn array[size-1];}public Integer pop() {if(size==0)throw new ArrayIndexOutOfBoundsException("The queue is empty");elsereturn array[--size];}
}	public class ArrayToStack {public static void main(String[] args) {ArrayStack as=new ArrayStack(3);as.push(3);System.out.println("peek:"+as.peek());as.push(24);System.out.println("pop:"+as.pop());System.out.println("pop:"+as.pop());//System.out.println("pop:"+as.pop());}	
}

运行结果:

若为注释掉最后一句pop,运行结果为:

4.2 实现队列

4.2.1 分析

如果一个数要入队列,若size

如果一个数要出队列,若size>0,则array[first]位置上的数出队列,同时first++;否则报错。

注:当last和first到达最后一个元素时,让它们下一个位置为0位置。

(last和first之间无关系)

4.2.2 代码实现

package Solution;class ArrayQueue{Integer[] array;Integer first;//出队列时的下标Integer last;//入队列时的下标Integer size;public ArrayQueue(int initsize) {if(initsize<0)throw new IllegalArgumentException("The init size is less than 0");elsearray=new Integer[initsize];size=0;last=0;first=0;}public void push(int num) {if(size==array.length)throw new ArrayIndexOutOfBoundsException("The queue is full");else {array[last]=num;last=last==array.length-1?0:last+1;size++;}}public Integer peek() {if(size==0)throw new ArrayIndexOutOfBoundsException("The queue is empty");else return array[first];}public Integer poll() {if(size==0)throw new ArrayIndexOutOfBoundsException("The queue is empty");else {size--;first=first==array.length-1?0:first+1;return array[first];}}
}
public class ArrayToQueue {public static void main(String[] args) {ArrayQueue as=new ArrayQueue(3);as.push(7);System.out.println("peek:"+as.peek());as.push(6);System.out.println("pop:"+as.poll());//7出as.push(5);as.push(9);//as.push(4);System.out.println("pop:"+as.poll());//6System.out.println("pop:"+as.poll());//5}
}

运行结果:

5. 实现一个特殊的栈, 在实现栈的基本功能的基础上, 再实现返回栈中最小元素的操作。

【要求】
1. pop、 push、 getMin操作的时间复杂度都是O(1)。
2. 设计的栈类型可以使用现成的栈结构。

5.1 方法一

5.1.1 分析:

准备两个栈:data、min

入栈:

第一个元素,压入data、min栈;

后面剩余元素,依次压入data栈;若当前入栈元素比min栈栈顶元素小,则入min栈,否则再一次压入min栈栈顶元素。

出栈:

两个栈同时弹出元素。

5.1.2 代码实现

package Solution;import java.util.Stack;class MyStack{Stack data;Stack min;public MyStack() {this.data=new Stack();this.min=new Stack();}public void push(int num) {if(data.isEmpty()) {data.push(num);min.push(num);}if(num<=min.peek()) {data.push(num);min.push(num);}else {data.push(num);min.push(min.peek());}}public Integer pop() {if(data.isEmpty())throw new RuntimeException("Your stack is empty.");min.pop();return data.pop();}public Integer getMin() {if(data.isEmpty())throw new RuntimeException("Your stack is empty.");return min.peek();}
}
public class StackGetMin {public static void main(String[] args) {MyStack ms=new MyStack();ms.push(4);ms.push(5);ms.push(3);ms.push(6);System.out.println("min:"+ms.getMin());System.out.println(ms.pop());System.out.println(ms.pop());System.out.println("min:"+ms.getMin());}
}

运行结果:

5.2 方法二

5.2.1 分析:

准备两个栈:data、min

入栈:

第一个元素,压入data、min栈;

后面剩余元素,依次压入data栈;若当前入栈元素比min栈栈顶元素小,则入min栈,否则不如min栈。

出栈:

若当前弹出的data栈顶元素=min栈栈顶元素,两个栈都弹出栈顶元素,否则只有data栈弹出栈顶元素。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部