左神_中级班_03

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);
            }
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值