奇妙的算法每个小孩的糖果数,找公约数,最少硬币数

Posted mufasa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了奇妙的算法每个小孩的糖果数,找公约数,最少硬币数相关的知识,希望对你有一定的参考价值。

1,每个小孩的糖果数量是多少

  有p个小孩,c个糖果,刚开始第1个小孩发一个糖果,第2个小孩发两个糖果,第p个小孩发p个糖果,如果糖果没有发完,就接着【注意】第1个小孩发p+1个糖果.....第p个小孩发2*p个糖果,如果糖果还没有发完,就继续下一轮,第1个小孩发2*p+1个糖果,...

方法一,遍历【这种方法太low了就折叠一下】

技术图片
package com.cnblogs.mufasa.Main1;

import java.util.Scanner;

public class Main 
    public static int[] getCandies(int c,int p)
        int[] pGet=new int[p];
        int preNum=1;
        while (c!=0)
            for(int i=0;i<p;i++)
                if(preNum<c)
                    pGet[i]+=preNum;
                    c-=preNum;
                    preNum++;
                else 
                    pGet[i]+=c;
                    return pGet;
                
            
        
        return null;
    

    public static void main(String[] args) 
        Scanner sc=new Scanner(System.in);
        int c=Integer.valueOf(sc.next());
        int p=Integer.valueOf(sc.next());
        int[] pGet=getCandies(c,p);
        System.out.print("[");
        for(int i=0;i<p-1;i++)
            System.out.print(pGet[i]+",");
        
        System.out.println(pGet[p-1]+"]");
    

/*
7
4
 */
View Code

方法二,数学推导【算法复杂度急速降低】除了,推理的时候复杂一些,其他都还好

package com.cnblogs.mufasa.Main1;

import java.util.Scanner;

public class Main1 
    public static void main(String[] args) 
        Scanner sc = new Scanner(System.in);
//        int c = Integer.valueOf(sc.next());
//        int p = Integer.valueOf(sc.next());

        //0,测试
        int c=45,p=4;

        int lineSum=(1+p)*p/2;//1+2+3+...+p的总数
        int leve=0,preCan=c;

        //1,1先判断出是在第几层中断【正确】
        while (true)
            if(preCan<leve*p*p+lineSum)
                break;
            
            preCan-=(leve*p*p+lineSum);
            leve++;
        

        int[] pGet=new int[p];

        //1,2直接算出各个小朋友持有的糖果数【还是要区分第0层与其他层的区别】
        if(leve!=0)//1,2,2  非第0层中断
            int temp=p*(leve-1)*leve/2;
            for(int i=1;i<=p;i++)
                pGet[i-1]=temp+i*leve;
            
        

        int preSta=p*leve;
        for(int i=1;i<=p;i++)
            if(preCan<preSta+i)
                pGet[i-1]+=preCan;
                break;
            else 
                pGet[i-1]+=(preSta+i);
            
            preCan-=(preSta+i);
        

        //3数据输出
        System.out.print("[");
        for(int i=0;i<p-1;i++)
            System.out.print(pGet[i]+",");
        
        System.out.println(pGet[p-1]+"]");
    

 

2,找两个数组公有的数

方法一:使用HashSet和TreeSet解决问题,但是只AC60%!!!可能是耗时太多【时间复杂度大】理解简单易懂

技术图片
package com.cnblogs.mufasa.Main2;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Scanner;
import java.util.TreeSet;

public class Main 
    public static void main(String[] args) 
        Scanner sc=new Scanner(System.in);
        String str0=sc.next();
        String str1=sc.next();

        String[] strs0=str0.substring(1,str0.length()-1).split(",");
        String[] strs1=str1.substring(1,str1.length()-1).split(",");

        if(str0.length()<str1.length())
            String[] temp=strs0;
            strs0=strs1;
            strs1=temp;
        

        HashSet<Integer> hs=new HashSet<>();
        TreeSet<Integer> tsOut=new TreeSet<>();
        for(int i=0;i<strs0.length;i++)
            hs.add(Integer.valueOf(strs0[i]));
        

        for(int i=0;i<strs1.length;i++)
            int temp=Integer.valueOf(strs1[i]);
            if(hs.contains(temp))
                tsOut.add(temp);
            
        

        System.out.print("[");
        for(int i=0;i<tsOut.size()-1;i++)
            System.out.print(tsOut.pollFirst()+",");
        
        System.out.print(tsOut.pollFirst());
        System.out.println("]");
    

/*
[1,2,2,1,3]
[2,2,3]

[2,3]
 */
View Code

方法二:直接使用遍历进行,省略了计算hash值以及进行查找的费时操作【算法复杂度降低并且拥有两个光标进行判断】

package com.cnblogs.mufasa.Main2_1;

import java.util.*;

public class Main 
    public static void main(String[] args) 
        Scanner sc=new Scanner(System.in);
//        String str0=sc.next();
//        String str1=sc.next();

        //测试
        String str0="[1,2,2,1,3]";
        String str1="[2,2,3]";

        String[] strs0=str0.substring(1,str0.length()-1).split(",");
        String[] strs1=str1.substring(1,str1.length()-1).split(",");

        if(str0.length()<str1.length())
            String[] temp=strs0;
            strs0=strs1;
            strs1=temp;
        

        int[] arr0=new int[strs0.length];
        int[] arr1=new int[strs1.length];
        for(int i=0;i<arr0.length;i++)
            arr0[i]=Integer.valueOf(strs0[i]);
        
        for(int i=0;i<arr1.length;i++)
            arr1[i]=Integer.valueOf(strs1[i]);
        

        Arrays.sort(arr0);//排序
        Arrays.sort(arr1);

        ArrayList<Integer> tsOut=new ArrayList<>();
        int index0=0,index1=0;
        while (index0<arr0.length&&index1<arr1.length)
            if(arr0[index0]==arr1[index1])
                if(!tsOut.contains(arr0[index0]))
                    tsOut.add(arr0[index0]);
                
                index0++;
            else if(arr0[index0]<arr1[index1])
                index0++;
            else 
                index1++;
            
        

        System.out.print("[");
        for(int i=0;i<tsOut.size()-1;i++)
            System.out.print(tsOut.get(i)+",");
        
        System.out.print(tsOut.get(tsOut.size()-1));
        System.out.println("]");
    

/*
[1,2,2,1,3]
[2,2,3]

[2,3]
 */

 

3,最少几个硬币找零

  例如:有1,2,5面值的硬币,请问11元钱最少多少硬币可以凑成,如果无法凑成直接输出-1【之前AC80%原因找到了,是输出-1这个没有安排上】

package com.cnblogs.mufasa.Main3;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Scanner;
import java.util.Stack;

//递归调用,好像可以很好的解决问题
public class Main 
    private final static int NUM=Integer.MAX_VALUE;
    private static Stack<Integer> stack=new Stack<>();
    static 
        stack.push(NUM);
    

    public static int sinFin(int[] sinM,int m,int num,int index)
        if(num>stack.peek())
            return NUM;
        

        if(m==0)//1,1钱已经凑够
            stack.push(num);
            return num;
        else if(index==0&&m%sinM[0]!=0)//1,2达到终点,但是不能凑成整数倍,返回一个最大值
            return -1;
        else if(index==0&&m%sinM[0]==0)//1,3到达终点,并且凑整数
            stack.push(num+m/sinM[0]);
            return num+m/sinM[0];
        

        int bei=m/sinM[index];
        ArrayList<Integer> arr=new ArrayList<>();
        for(int i=0;i<=bei;i++)
            arr.add(sinFin(sinM,m-sinM[index]*i,num+i,index-1));
        

        arr.sort((a,b)->
            return a-b;
        );
        for(int temp:arr)
            if(temp>0)
                return temp;
            
        
        return -1;
    

    public static void main(String[] args) 
        Scanner sc=new Scanner(System.in);
        String str0=sc.nextLine().replace(" ","");
        String str1=sc.next();

        String[] strs=str0.substring(1,str0.length()-1).split(",");
        int[] sinM=new int[strs.length];

        for(int i=0;i<strs.length;i++)
            sinM[i]=Integer.valueOf(strs[i]);
        

        int m=Integer.valueOf(str1);

        System.out.println(sinFin(sinM,m,0,sinM.length-1));

    


/*
[1, 2, 5]
11

3

[2, 4, 6]
11

 */

 

以上是关于奇妙的算法每个小孩的糖果数,找公约数,最少硬币数的主要内容,如果未能解决你的问题,请参考以下文章

GEEK编程练习— —发糖果问题

135. Candy

硬币找零问题的动态规划实现

分糖果

LeetCode 5219. 每个小孩最多能分到多少糖果

135. 分发糖果贪心算法