zoukankan      html  css  js  c++  java
  • 加减操作使数组中至少有k个数相同(贪心)

    题目描述:

    一维数组中由n个数,执行加减操作,目标是使n个数中至少有k个数相同,问最少需要多少次才能达到目标。加减操作的规则是:

    1)每次对最大的数减1

    2)每次对最小的数加1

    3)每次只能完成上述两个操作的一个。

    输入描述:第一行为n和k,第二行为数组的值。

    输出描述:最少需要多少次操作才能达到目标。

    示例输入:6 5 1 2 2 4 2 3

    输出:3

    题解参考:(先Mark一下,代码还没看懂,以后学完了贪心再回来看看!)

    package acm;
     
    import java.util.*;
     
    public class Main {
        public static void main(String[] args) {
            Scanner sc=new Scanner(System.in);
            int n=sc.nextInt(),k=sc.nextInt();
            int sum=0;
            int[] data=new int[n];
            for(int i=0;i<n;i++){
                data[i]=sc.nextInt();
                sum+=data[i];
            }
            Arrays.sort(data);
            int p=-1;
            int ans=Integer.MAX_VALUE;
            int pre=0;
            //最终的结果肯定是要有某个数出现的个数>=k,把这个数叫做基准数
            for(int i=0;i<n;){
                p=i;
                while(p<n&&data[p]==data[i]){
                    sum-=data[i];
                    p++;
                }
                int ned=Math.max(0,k-p+i);
                //ned的含义是目前如果让data[i]作为基准数,还差多少个达到k,如果为0说明已经超过k个了,也就是说不需要任何操作就可以满足题意要求
                if(ned==0){
                    ans=0;
    //                break;
                }
                if(p>=k){//p>=k说明以data[i]为基准数,调整下标i之前的数到达基准数,就可以满足题意,求出这时候需要操作个数
                    ans=Math.min(ans,i*data[i]-pre-(i-ned));//pre记录的是下标i之前的所有数字之和,要把下标i之前的数调整到等于基准数data[i],操作次数=i*data[i]-pre
                    //同时要考虑只需要k个满足就可以了,也就是这时候可以有i-ned不满足,也就是i-ned个数可以调整等于data[i]-1,所以要减去i-ned.
                }
                if(n-i>=k){//i往后的数字降到data[i]就直接可以满足题意,与p>=k类似,只是调整方向不一样
                    ans=Math.min(ans,sum-(n-p)*data[i]-(n-p-ned));//
                }
                ans=Math.min(ans,i*data[i]-pre+sum-(n-p)*data[i]-(n-(p-i)-ned));//同时需要判断两边都做操作的情况下调整的个数
                pre+=data[i]*(p-i);//pre加上data[i]乘以data[i]的个数,那么下一步i=p的时候pre就代表i之前所有数之和。
                i=p;
            }
            System.out.println(ans);
        }
     
    }
    Demo 1
    public class Test {
     
        public static void main(String[] args) {
            // input
            Scanner scanner = new Scanner(System.in);
            int n = scanner.nextInt();
            int k = scanner.nextInt();
            int[] data = new int[n];
            for(int i=0; i<n; i++) {
                data[i] = scanner.nextInt();
            }
            Arrays.sort(data);
     
            // cal result from two paths
            int res1 = 0;
            int res2 = 0;
            for (int i = 0; i < k; i++) {
                // 若把所有较小高度补到第 k 大的高度,需要的步数
                res1 += (data[k-1] - data[i]);
                // 若把所有较大高度削到倒数第 k 大的高度,需要的步数
                res2 += (data[n-1-i] - data[n-1-k+1]);
            }
            int index1=k, index2=n-1-k;
            // 如果第 k 大的高度 h1 在后面的数值中还重复出现了 m 次
            // 则说明多进行了 m 次操作
            while(index1<n && data[index1++]==data[k-1]) res1--;
            // 如果倒数第 k 大的高度 h2 在后面的数值中还重复出现了 l 次
            // 则说明多进行了 l 次操作
            while(index2>=0 && data[index2--]==data[n-1-k+1]) res2--;
            // 如果 res1 和 res2 中有负值
            // 则说明在一开始第 k 大或倒数第 k 大的高度就已经有了 k 个
            // 此时返回0
            System.out.println(Math.max(0, Math.min(res1, res2)));
        }
     
    }
    Demo 2
    public class Test {
        public static void main(String[] args) {
            Scanner scan=new Scanner(System.in);
            int N=scan.nextInt();
            int k=scan.nextInt();
            scan.nextLine();
            int [] arr=new int[N];
            for(int i=0;i<N;i++){
                arr[i]=scan.nextInt();
            }
            Arrays.sort(arr);
            int result = beginGame(arr, N, k);
            System.out.println(result);
        }
    
        private static int beginGame(int[] arr, int N, int k) {
    
            int path1 = 0;
            int path2 = 0;
    
            for (int i=0;i<k;i++){
                path1+=arr[k-1]-arr[i];
                path2+=arr[N-i-1]-arr[N-k];
            }
    
            int index1=k;
            int index2=N-k-1;
            while(index1<N&&arr[index1++]==arr[k-1]){
               path1--;
            }
            while(index2>=0&&arr[index2--]==arr[N-k]){
                path2--;
            }
            return Math.min(path1, path2);
        }
    }
    Demo 3
  • 相关阅读:
    单例模式
    spring boot 调度任务
    linux yum安装MySQL5.6
    day5模块学习--sys模块
    day5模块学习 -- os模块学习
    day5模块学习--random模块
    day5模块学习 -- time、datetime时间模块
    生成随机验证码的方法
    SQL中format()函数对应的格式
    day4作业小代码练习
  • 原文地址:https://www.cnblogs.com/HuangYJ/p/12809514.html
Copyright © 2011-2022 走看看