1.洗衣机问题:每个位置的瓶颈的最大值
求出每个位置左边需求,与右边需求
(1)若左<0,右<0: 至少|左|+|右|
(2)若其他: 至少max(|左|+|右|)
public static int MinOps(int[] arr) {
if(arr==null||arr.length==0){
return 0;
}
int sum=0;
for (int i : arr) {
sum+=i;
}
int size=arr.length;
if(sum%size!=0){
return -1;
}
int avg=sum/size;
int leftSum=0;
int ans=0;
for(int i=0;i<size;i++){
int L=leftSum-i*avg; //左边需求:已有的-要求的
int R=(sum-leftSum-arr[i])-avg*(size-i-1);//右边需求:已有的-要求的
if(L<0&&R<0){
ans=Math.max(ans,Math.abs(L)+Math.abs(R));
}else{
ans=Math.max(ans,Math.max(Math.abs(L),Math.abs(R)));
}
leftSum+=arr[i];
}
return ans;
}
2.以zigzag的方式打印矩阵
public static void printMatrixZigZag(int[][] matrix) {
int ar=0;
int ac=0;
int br=0;
int bc=0;
int endr=matrix.length-1;
int endc=matrix[0].length-1;
boolean up=true; //为真,从下往上打印
while(ar!=endr+1){
printLevel(matrix,ar,ac,br,bc,up);
ar= ac==endc? ar+1:ar;//注意ar和ac的赋值顺序不能相反
ac= ac==endc? ac:ac+1;
bc= br==endr? bc+1:bc;//注意br和bc的赋值顺序不能相反
br= br==endr? br:br+1;
up=!up;
}
System.out.println();
}
public static void printLevel(int[][] m, int arr, int acc, int brr, int bcc,
boolean up) {
if(up){
while(brr!=arr-1){
System.out.print(m[brr--][bcc++]+" ");
}
}else{
while (arr!=brr+1){
System.out.print(m[arr++][acc--]+" ");
}
}
}
3.螺旋的方式打印矩阵
固定左上角和右下角,先打印一圈,再左上角向右下角移动,右下角向右上角移动
public static void spiralOrderPrint(int[][] matrix) {
int ta=0;
int tb=0;//左上角的点
int tc=matrix[0].length-1;
int td=matrix[0].length-1;//右下角的点
while(ta<=tc&&tb<=td){
printEdge(matrix,ta,tb,tc,td);
ta++;
tb++;
tc--;
td--;
}
}
public static void printEdge(int[][] m, int a, int b, int c, int d) {
if(a==c){//边界条件,左上角与右下角同行
for(int i=b;i<=d;i++){
System.out.println(m[a][i]+" ");
}
}else if(b==d){//边界条件,左上角与右下角同列
for(int i=a;i<=c;i++){
System.out.println(m[i][b]+" ");
}
}else{//普通情况,打印一圈
int cura=a;
int curb=b;
while(curb!=d){
System.out.println(m[cura][curb]+" ");
curb++;
}
while(cura!=c){
System.out.println(m[cura][curb]+" ");
cura++;
}
while(curb!=b){
System.out.println(m[cura][curb]+" ");
curb--;
}
while(cura!=a){
System.out.println(m[cura][curb]+" ");
cura--;
}
}
}
4.给定一个正方形矩阵,只用有限几个变量,实现矩阵中每个位置的数顺时针转动90度,比如如下的矩阵
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
矩阵应该被调整为:
12 8 4 0
13 9 5 1
14 10 6 2
15 11 7 3
public static void rotate(int[][] matrix) {
int ia=0;
int ib=0;
int ic=matrix[0].length-1;
int id=matrix[0].length-1;
while(ia<=ic&&ib<=id){
rotateEdge(matrix,ia,ib,ic,id);
ia++;
ib++;
ic--;
id--;
}
}
public static void rotateEdge(int[][] m, int a, int b, int c, int d) {
int temp=0;
for(int i=0;i<d-b;i++){
temp=m[a][b+i];
m[a][b+i]=m[c-i][b];
m[c-i][b]=m[c][d-i];
m[c][d-i]=m[a+i][d];
m[a+i][d]=temp;
}
}
5.二维数组matrix,每行每列从小到大有序,判断整数aim是否在数组中
public static boolean isContains(int[][] matrix,int k){
int m=matrix.length;
int n=matrix[0].length;
int i=0;
int j=n-1;
while(i<=m-1&&j>=0){
if(matrix[i][j]==k){
return true;
}
if(matrix[i][j]>k){
j=j-1;
}
if(matrix[i][j]<k){
i=i+1;
}
}
return false;
}
6.假设s和m初始化, s = “a”; m = s;
再定义两种操作, 第一种操作:
m = s;
s = s + s;
第二种操作:
s = s + m;
求最小的操作步骤数, 可以将s拼接到长度等于n
解:若n为质数,返回n-1
若n为合数,则一定能分解为全为质数的因数(20=2 * 2 * 5),返回质数因数的和-质数个数(2+2+5-3=6)
// 附加题:怎么判断一个数是不是质数?
public static boolean isPrim(int n) {
if(n<2){
return false;
}
int max=(int)Math.sqrt((double) n);
for(int i=2;i<=max;i++){
if(n%i==0){ //注意是%操作
return false;
}
}
return true;
}
// 请保证n不是质数
// 返回:
// 0) 所有因子的和,但是因子不包括1
// 1) 所有因子的个数,但是因子不包括1
public static int[] divsSumAndCount(int n) {
int sum=0;
int count=0;
for(int i=2;i<=n;i++){
while(n%i==0){ //注意是while
sum+=i;
count++;
n/=i;
}
}
return new int[]{sum,count};
}
public static int minOps(int n) {
if(n<2){
return 0;
}
if(isPrim(n)){
return n-1;
}
int[] ints = divsSumAndCount(n);
return ints[0]-ints[1];
}
public static void main(String[] args) {
int n=20;
System.out.println(minOps(n));
}
7.给定一个字符串类型的数组arr,求其中出现的次数最多的前K个
(1)map统计词频,抽象成节点(字符串,次数)放入大根堆,从大根堆取出前k个
public static class Node {
String string;
Integer num;
public Node(String string, Integer num) {
this.string = string;
this.num = num;
}
private static void printTopKAndRank(String[] arr1, int k) {
if (arr1 == null || k <= 0 || arr1.length == 0) {
return;
}
HashMap<String, Integer> hashMap = new HashMap<>();
for (String s : arr1) {
if (hashMap.containsKey(s)) {
hashMap.put(s, hashMap.get(s) + 1);
} else {
hashMap.put(s, 1);
}
}
//大根堆
PriorityQueue<Node> nodes = new PriorityQueue<Node>(new Comparator<Node>() {
@Override
public int compare(Node o1, Node o2) {
return o2.num - o1.num;
}
});
for (Entry<String, Integer> entry : hashMap.entrySet()) {
nodes.add(new Node(entry.getKey(), entry.getValue()));
}
for (int i = 0; i < k; i++) {
Node poll = nodes.poll();
System.out.println(poll.string + " " + poll.num);
}
}
(2)map统计词频,抽象成节点(字符串,次数)放入小根堆(限制空间为k,永远存放当前num最大的k个节点,堆顶就是个门槛),来的节点只有num大于等于堆顶,才能放入堆
private static void printTopKAndRank(String[] arr1, int k) {
if (arr1 == null || k <= 0 || arr1.length == 0) {
return;
}
HashMap<String, Integer> hashMap = new HashMap<>();
for (String s : arr1) {
if (hashMap.containsKey(s)) {
hashMap.put(s, hashMap.get(s) + 1);
} else {
hashMap.put(s, 1);
}
}
//小根堆
PriorityQueue<Node> nodes = new PriorityQueue<Node>(k,new Comparator<Node>() {
@Override
public int compare(Node o1, Node o2) {
return o1.num - o2.num;
}
});
for (Entry<String, Integer> entry : hashMap.entrySet()) {
Node node = new Node(entry.getKey(), entry.getValue());
if (nodes.size()<k){
nodes.add(node);
}else{
if(node.num>=nodes.peek().num){
nodes.poll();
nodes.add(node);
}
}
}
for (int i = 0; i < k; i++) {
Node poll = nodes.poll();
System.out.println(poll.string + " " + poll.num);
}
}
7.补充题目:设计一个结构,可以往里添加字符串,并且可以随时打印出现次数最多的K的数
解法:词频表,堆,堆位置表
public static class Node{
public String str;
public Integer times;
public Node(String s,Integer t){
this.str=s;
this.times=t;
}
}
public static class TopKRecord{
private Node[] heap;
private int index;
private HashMap<String,Node> strNodeMap;
private HashMap<Node,Integer> nodeIndexMap;
public TopKRecord(int size){
heap=new Node[size];//堆
index=0;//堆的大小
strNodeMap=new HashMap<String,Node>();//词频表
nodeIndexMap=new HashMap<Node,Integer>();//堆位置map
}
public void add(String str){
//当前str对应的节点对象
Node curNode=null;
//当前str对应的节点对象是否在堆上
int preIndex=-1;
if(!strNodeMap.containsKey(str)){//词频表不包括该字符串,说明没出现过
curNode=new Node(str,1);
strNodeMap.put(str,curNode);
nodeIndexMap.put(curNode,-1);
}else{//词频表包括该字符串,说明出现过,从堆位置map取出该节点在堆中的位置
curNode=strNodeMap.get(str);
curNode.times++;
preIndex=nodeIndexMap.get(curNode);
}
if(preIndex==-1){//没出现过
if(index==heap.length){//堆满了
if(curNode.times>heap[0].times){//当前节点次数大于堆顶元素次数
nodeIndexMap.put(heap[0],-1);
nodeIndexMap.put(curNode,0);
heap[0]=curNode;
heapify(0,index);
}
}else{//堆没满,直接加入
nodeIndexMap.put(curNode,index);
heap[index]=curNode;
heapInsert(index++);
}
}else{//当前节点已经在堆上了,直接调整
heapify(preIndex,index);
}
}
private void heapify(int index,int heapSize){
int l=index*2 +1;
int r=index*2 +2;
int smallest=index;
while(l<heapSize){
if(heap[l].times<heap[index].times){
smallest=l;
}
if(r<heapSize&&heap[r].times<heap[smallest].times){
smallest=r;
}
if(smallest!=index){
swap(smallest,index);
}else{
break;
}
index=smallest;
l=index*2+1;
r=index*2 +2;
}
}
private void heapInsert(int index){
while (index!=0){
int parent=(index-1)/2;
if(heap[index].times<heap[parent].times){
swap(parent,index);
index=parent;
}else{
break;
}
}
}
private void swap(int index1,int index2){ //堆位置map和堆都要变
nodeIndexMap.put(heap[index1],index2);
nodeIndexMap.put(heap[index2],index1);
Node temp=heap[index1];
heap[index1]=heap[index2];
heap[index2]=temp;
}
public void printTopK(){
System.out.println("TOP:");
for(int i=0;i!=heap.length;i++){
if(heap[i]==null){
break;
}
System.out.println("Str: "+heap[i].str);
System.out.println("Times: "+heap[i].times);
}
}