leetcode 11

这篇博客主要介绍了两个Java类:ReceiveAndPrintOrderList用于接收和打印连续编号的信息,以及MoneyWays解决给定金额的找零问题。同时,还探讨了数位动态规划(DP)模型,讲解了如何将递归转换为非递归形式,并提供了求解数字中1的个数的算法,其时间复杂度为O(logN*logN)。
摘要由CSDN通过智能技术生成

在这里插入图片描述

import java.util.HashMap;

public class ReceiveAndPrintOrderList {
    public static class Node{
        public String info;
        public Node next;

        public Node(String str){
            info = str;
        }
    }

    public static class MessageBox{
        //连续区间的开头和结尾
        private HashMap<Integer,Node> headMap;
        private HashMap<Integer,Node> tailMap;
        //等待几号信息
        private int waitPoint;

        public MessageBox(){
            headMap = new HashMap<>();
            tailMap = new HashMap<>();
            waitPoint = 1;
        }

        /**
         *
         * @param num 接受信息的编号
         * @param info 接受信息的内容
         */
        public void receive(int num,String info){
           if(num < 1){ //所有的编号从1开始
               return;
           }

           //封装一个节点
           Node cur = new Node(info);
           headMap.put(num,cur);
           tailMap.put(num,cur);

           //之前有没有num—1结尾的
           if(tailMap.containsKey(num-1)){
               tailMap.get(num-1).next = cur;
               tailMap.remove(num-1);
               headMap.remove(num);
           }
           //动手画图就明白了
            if(headMap.containsKey(num+1)){
                cur.next = headMap.get(num+1);
                headMap.remove(num+1);
                tailMap.remove(num);
            }

           if(num == waitPoint){
               print();
           }
        }

        private void print(){
            Node node = headMap.get(waitPoint);
            //去除打印的开头和结尾
            headMap.remove(waitPoint);
            while(node != null){
                System.out.println(node.info+" ");
                node = node.next;
                waitPoint++;
            }
            tailMap.remove(waitPoint-1);
            System.out.println();
        }

在这里插入图片描述

public class MoneyWays {

    public static int moneyWays(int[] aribitary,int[] onlyone,int money){
        if(money < 0){
            return 0;
        }

        if((aribitary == null) || aribitary.length == 0)&&(onlyone==null||onlyone.length == 0)){
            return money == 0 ? 1 : 0;
        }

        int[][] dparb = getDpArb(aribitary,money);
        int[][] dpone = getDpOne(onlyone,money);
        if(dparb == null){
            return dpone[dpone.length][money];
        }
        if(dpone == null){
            return dpone[dparb.length][money];
        }
        int res = 0;
        for (int i = 0; i < money; i++) {
            res += dparb[dparb.length-1][i]*dpone[dpone.length-1][money-i];
        }
        return res;
    }
    //选择面值 可以重复选择
    public static int[][] getDpArb(int[] arr,int money){
        if(arr == null || arr.length == 0){
            return null;
        }
        int[][] dp = new int[arr.length][money+1];

        for (int i = 0; i < arr.length; i++) {
            dp[i][0] = 1;
        }

        for(int j = 1;arr[0] * j <= money;j++){
            dp[0][arr[0] * j] = 1;
        }

        for(int i = 1; i < arr.length;i++){
            for(int j = 1;j <= money;j++){
                dp[i][j] = dp[i-1][j];
                dp[i][j] += j - arr[i] >= 0 ?dp[i][j-arr[i]]:0;
            }
        }
        return dp;
    }
    public static int[][] getDpOne(int[] arr,int money) {
        if (arr == null || arr.length == 0) {
            return null;
        }
        int[][] dp = new int[arr.length][money + 1];

        for (int i = 0; i < arr.length; i++) {
            dp[i][0] = 1;
        }

        for (int j = 1; arr[0] * j <= money; j++) {
            dp[0][arr[0] * j] = 1;
        }

        //我自己改的 不知道对不 理论上对
        for (int i = 1; i < arr.length; i++) {
            for (int j = 1; j <= money; j++) {
                dp[i][j] = dp[i - 1][j];
                dp[i][j] = j - arr[i] >= 0 ? dp[i][j - arr[i]] : 0;
            }
        }
        return dp;
    }
}

在这里插入图片描述
数位dp模型
转非递归形式
比如N=3625 f(n)为数字为n有多少个1,f(3625) = f(625)+{626到3625),f(625)依次往下分解
如果最高位是1,最高位1的数量是N%(10^(k-1))+1 一共k位
剩下的位数为1的总和是 (k-1)*(10^(k-2))
最高位不是1的情况
比如730~5729
(1)730~1729
(2)1730~2729
(3)2730~3729
(4)3730~4729
总共1的数量是 1 0 k − 2 ∗ a ∗ ( k − 1 ) + 1 0 k − 1 ( 加 上 的 10 的 k − 1 次 方 是 最 高 位 为 1 的 情 况 10^{k-2}*a*(k-1)+10^{k-1}(加上的10的k-1次方是最高位为1的情况 10k2a(k1)+10k110k11
上述算法针对的是一个区间,因为是区间递归下一个区间
时间复杂度log10(N)*log10(N)

不常考5%的小概率常考的
public class OneNumber {
    public static int solution2(int num){
        if(num < 1){
            return 0;
        }
        //求num的位数 代价log10N
        int len = genLenOfNum(num);
        if(len == 1){
            return 1;
        }
        //num  88998989
        //tmp1 10000000
        int tmp1 = powerBaseOf10(len-1);
        //num最高位
        int first = num / tmp1;
        //最高位是1   N%tmp1+1
        //最高位first  tmp1
        int firstOneNumber = first == 1 ? num % tmp1 + 1:tmp1;
        //除最高位之外 剩下1的数量
        //最高位1   10(k-2次方)*(k-1) * 1
        //最高位first 10(k-2次方)*(k-1)*first
        int otherOneNumber = first * (len-1) * (tmp1/10);

        return firstOneNumber + otherOneNumber + solution2(num % tmp1);
    }
    
    public static int genLenOfNum(int num){
        int len = 0;
        while(num != 0){
            len++;
            num /= 10;
        }
        return len;
    }
    
    public static int powerBaseOf10(int base){
        return (int)Math.pow(10,base);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值