无规律总结的算法题

1.魔术操作

给一个包含n个整数元素的集合a,一个包含m个整数元素的集合b。 定义magic操作为,从一个集合中取出一个元素,放到另一个集合里,且操作过后每个集合的平均值都大于操作前。 注意以下两点: 1)不可以把一个集合的元素取空,这样就没有平均值了 2)值为x的元素从集合b取出放入集合a,但集合a中已经有值为x的元素,则a的 平均值不变(因为集合元素不会重复),b的平均值可能会改变(因为x被取出了) 问最多可以进行多少次操作

思想:要使取完一个数后 两个集合的平均值都变大 则只能取两个平均值之间的数字。

	// 请保证arr1无重复值、arr2中无重复值,且arr1和arr2肯定有数字
	public static int maxOps(int[] arr1, int[] arr2) {
   
		double sum1 = 0;
		for (int i = 0; i < arr1.length; i++) {
   
			sum1 += (double) arr1[i];
		}
		double sum2 = 0;
		for (int i = 0; i < arr2.length; i++) {
   
			sum2 += (double) arr2[i];
		}
        //判断两个集合的平均值是否一样 如果一样 则不能取 怎么取都要使其中一个变小
		if (avg(sum1, arr1.length) == avg(sum2, arr2.length)) 
			return 0;
        //下面操作就是进行重定位 重新赋值一下 方便整理
		int[] arrMore = null;
		int[] arrLess = null;
		double sumMore = 0;
		double sumLess = 0;
		if (avg(sum1, arr1.length) > avg(sum2, arr2.length)) {
   
			arrMore = arr1;
			sumMore = sum1;
			arrLess = arr2;
			sumLess = sum2;
		} else {
   
			arrMore = arr2;
			sumMore = sum2;
			arrLess = arr1;
			sumLess = sum1;
		}
        //排序大的数组 为什么不排序小的数组呢?因为只能从大数组当中取数据
		Arrays.sort(arrMore);
		HashSet<Integer> setLess = new HashSet<>();
		for (int num : arrLess) setLess.add(num);
		int moreSize = arrMore.length;
		int lessSize = arrLess.length;
		int ops = 0;
		for (int i = 0; i < arrMore.length; i++) {
   
			double cur = (double) arrMore[i];
            //当前值小于大数组平均值&&大于小数组的平均值&&小数组当中没有该元素 则把该数字放到小数组当中
			if (cur < avg(sumMore, moreSize) && cur > avg(sumLess, lessSize)
					&& !setLess.contains(arrMore[i])) {
   
				sumMore -= cur;
				moreSize--;
				sumLess += cur;
				lessSize++;
				setLess.add(arrMore[i]);
				ops++;
			}
		}
		return ops;
	}

	public static double avg(double sum, int size) {
   
		return sum / (double) (size);
	}

2.超级洗衣机

力扣地址

 public int findMinMoves(int[] machines) {
   
        int size = machines.length;
        int sum = 0;
        for (int i = 0; i < size; i++)
            sum += machines[i];//计算出总共的衣服
        if (sum % size != 0)  return -1;//如果每台机器不能均分 直接返回-1
        int avg = sum / size;//获得每台机器应该是多少个
        int leftSum = 0;//左边衣服和
        int ans = 0;
        for (int i = 0; i < machines.length; i++) {
   
            //获得左边已经有的衣服和需要衣服之差 如果差为+代表左边衣服太多了需要吐出来 否则需要收衣服
            int L = leftSum - avg*i ;
            //获得右边已经有的衣服和需要衣服之差 如果差为+代表左边衣服太多了需要吐出来 否则需要收衣服
            int R =  (sum - leftSum - machines[i])-(size - i - 1) * avg ;
            //如果当前位置两边都是负数 则当前位置必须吐衣服给两边 由于每次只能吐一件 则需要|L+R|次
            if (L < 0 && R < 0) 
                ans = Math.max(ans, Math.abs(L+R));
            //否则 一正一负 或者 两个都为正 都是下面这个 为什么呢?
            //一正一负 题目虽然说了 每台只能吐或者收 但是不同机器可以连续工作 你是一正一负 则可以变成一条线 需要的次数就是最大的那个数
            //eg: +6 2 -4 6往右边吐的时候 2也可以往-4那吐 但是6必须吐完 则需要6次 当为 +6 2 +7 则必须吐7次
            else 
                ans = Math.max(ans, Math.max(Math.abs(L), Math.abs(R)));
            leftSum += machines[i];//每次计算完 左边和累加
        }
        return ans;
    }

3.螺旋打印矩阵

力扣地址

 public int[] spiralOrder(int[][] matrix) {
   
       if(matrix.length==0||matrix[0].length==0) return new int[0];
       int[] res=new int[matrix.length*matrix[0].length];//需要的数组大小
       int x1=0,y1=0,x2=matrix.length-1,y2=matrix[0].length-1;//两个坐标的位置
       //当两个坐标的位置错开了 就说明打印完成了 不理解可以画个图
       while (x1 <= x2 && y1<=y2)
           print(matrix,x1++,y1++,x2--,y2--,res);
       return res;
   }
    //打印模板 每次是那一个圈中的两个点 左上角和右下角的点 每次只打印那一圈
    //根据传过来的两个坐标 顺时针打印2个点连成的矩阵
    int index=0;
    public void print(int[][] matrix, int x1, int y1, int x2, int y2, int[] list){
   
        //如果两个坐标一条横线上 则直接横线打印
        if(x1==x2)
            for (int i = y1; i <=y2 ; i++)
                list[index++]=matrix[x1][i];
            //如果两个坐标一条竖线上 则直接竖线打印
        else if(y1==y2)
            for (int i = x1; i <=x2 ; i++)
                list[index++]=matrix[i][y1];
        else{
   //否则说明两个坐标构成了矩形 则顺时针打印
            for (int i = y1; i <y2 ; i++)
                list[index++]=matrix[x1][i];
            for (int i = x1; i <x2 ; i++)
                list[index++]=matrix[i][y2];
            for (int i = y2; i >y1 ; i--)
                list[index++]=matrix[x2][i];
            for (int i = x2; i >x1 ; i--)
                list[index++]=matrix[i][y1];
        }
    }

4.旋转矩阵

力扣地址:跟上面那个螺旋打印矩阵类似 定义一个模板方法 只操作这一圈的数据

 public void rotate(int[][] matrix) {
   
        int x1=0,y1=0,x2=matrix.length-1,y2=matrix[0].length-1;//两个坐标的位置
        //当两个坐标的位置错开了 就说明旋转完成了 不理解可以画个图
        while (x1 <= x2 && y1<=y2)
            xunzhuan(matrix,x1++,y1++,x2--,y2--);
    }
    //旋转模板 每次是那一个圈中的两个点 左上角和右下角的点
    //根据传过来的两个坐标 旋转就行
    public void xunzhuan(int[][] matrix, int x1, int y1, int x2, int y2){
   
        //由于是n*n的矩阵 则不存在像打印螺旋矩阵那种需要判断是否是一根线
        //x2 - x1 代表每次那一圈需要操作几次
        for (int i = 0; i < x2 - x1; i++) {
   
            //每次交换那四个数的值
            int temp=matrix[x1+i][y2];
            matrix[x1+i][y2]=matrix[x1][y1+i];
            matrix[x1][y1+i]=matrix[x2-i][y1];
            matrix[x2-i][y1]=matrix[x2][y2-i];
            matrix[x2][y2-i]=temp;
        }
    }

5.实现一个最小栈

力扣地址

class MinStack {
   
        private Stack<Integer> minStack;//存放最小值的栈 
        private Stack
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值