LeetCode 279. 完全平方数 / 牛客:多多的数字组合 / 多多的字符变换

279. 完全平方数

2021.6.11每日一题

题目描述
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

给你一个整数 n ,返回和为 n 的完全平方数的 最少数量 。

完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。


示例 1:

输入:n = 12
输出:3 
解释:12 = 4 + 4 + 4
示例 2:

输入:n = 13
输出:2
解释:13 = 4 + 9

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/perfect-squares
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

还是完全背包问题吧,这次是求最少数量,所以排列数和组合数其实都无所谓,也就是两层循环可以换

class Solution {
    public int numSquares(int n) {
        int[] dp = new int[n + 1];
        Arrays.fill(dp, 10000);
        dp[0] = 0;
        //先遍历物品,再遍历目标值
        for(int i = 1; i * i <= n; i++){
            for(int j = i * i; j <= n; j++){
                dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
            }
        }
        return dp[n];
    }
}

接昨天,复习一下二维的

class Solution {
    public int numSquares(int n) {
        int t = 0;
        while(t * t <= n)
            t++;
        
        int[][] dp = new int[t][n + 1];
        for(int i = 1; i <= n; i++){
            dp[0][i] = n;
        }    

        //先遍历物品,再遍历目标值
        for(int i = 1; i < t; i++){
            for(int j = 1; j <= n; j++){
                dp[i][j] = dp[i - 1][j];
                if(j >= i * i)
                    dp[i][j] = Math.min(dp[i][j], dp[i][j - i * i] + 1);
            }
        }
        return dp[t - 1][n];
    }
}

多多的数字组合

题目描述
多多君最近在研究某种数字组合:
定义为:每个数字的十进制表示中(0~9),每个数位各不相同且各个数位之和等于N。
满足条件的数字可能很多,找到其中的最小值即可。
多多君还有很多研究课题,于是多多君找到了你--未来的计算机科学家寻求帮助。

输入描述:
共一行,一个正整数N,如题意所示,表示组合中数字不同数位之和。
(1 <= N <= 1,000)

输出描述:
共一行,一个整数,表示该组合中的最小值。
如果组合中没有任何符合条件的数字,那么输出-1即可。

输入例子1:
5

输出例子1:
5

例子说明1:
符合条件的数字有:5,14,23,32,41
其中最小值为5

输入例子2:
12

输出例子2:
39

例子说明2:


输入例子3:
50

输出例子3:
-1

例子说明3:
没有符合条件的数字 (T▽T)
思路

算是贪心吧,把最大的整数放在最后面,然后依次从后向前摆放剩下的数

import java.util.*;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt();
        if(N > (1 + 9) * 9 / 2)
            System.out.println(-1);
        else if(N <= 9)
            System.out.println(N);
        else{
            int res = 0;
            int base = 9;
            int q = 1;
            while(N > base){
                N -= base;
                res += base * q;
                q *= 10;
                base--;
            }
            if(N != 0){
                res += N * q;             
            }                
            System.out.println(res);
        } 
    }
}

多多的字符变换

多多君最近在研究字符串之间的变换,可以对字符串进行若干次变换操作:

交换任意两个相邻的字符,代价为0。
将任意一个字符a修改成字符b,代价为 |a - b|(绝对值)。
现在有两个长度相同的字符串X和Y,多多君想知道,如果要将X和Y变成两个一样的字符串,需要的最少的代价之和是多少。


输入描述:
共三行,第一行,一个整数N,表示字符串的长度。
(1 <= N <= 2,000)
接下来两行,每行分别是一个字符串,表示字符串X和Y。
(字符串中仅包含小写字母)

输出描述:
共一行,一个整数,表示将X和Y变换成一样的字符串需要的最小的总代价。

输入例子1:
4
abca
abcd

输出例子1:
3

例子说明1:
其中一种代价最小的变换方案:
都修改为abcd,那么将第一个字符串X最后一个字符a修改为d,代价为|a - d| = 3。

输入例子2:
4
baaa
aabb

输出例子2:
1

例子说明2:
其中一种代价最小的变换方案:
首先将第一个字符串通过交换相邻的字符:baaa -> abaa -> aaba,代价为0。
然后将第二个字符串修改最后一个字符b:|b - a| = 1。
两个字符都修改为aaba,所以最小的总代价为1。

输入例子3:
3
abc
xyz

输出例子3:
69
思路

这个题和上周周赛的题有点像,第一个操作代价为0,意思是第一个操作随便用
所以怎么说,主要还是看交换了,怎么样能使相同的字符尽量相对应

思考一个问题,就是如果x、y有相同的字符,是否交换相邻字符肯定能使两个字符串相同的字符对应起来
首先想到了三个字符(abc)的交换,是否能形成6种排列,想了一下确实可以abc,acb,bac,bca,cab,cba
那四个字符呢,相当于多加了一个字符,例如abcd,那么a开头,后面可以交换6种,b交换到a的位置,后面还是6种,…

所以得到结论,通过相邻字符交换,可以得到任意字符的排列
所以这个题就转换成了求两个字符串不同字符的差值
统计就完事了

思路是很好想,但是统计起来还是有点麻烦…可能是我写麻烦了,明天看下怎么能简洁一点

import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        sc.nextLine();      
        String x = sc.nextLine();
        String y = sc.nextLine();
        int[] countx = new int[26];
        int[] county = new int[26];
        for(int i = 0; i < n; i++){       
            countx[x.charAt(i) - 'a']++;
            county[y.charAt(i) - 'a']++;
        }
        
        int res = 0;
        //抵消掉相同的
        for(int i = 0; i < 26; i++){
            if(countx[i] >= county[i]){
                countx[i] -= county[i];
                county[i] = 0;
            }else{
                county[i] -= countx[i];
                countx[i] = 0;
            }      
        }
        int idx = 0;
        int idy = 0;
        while(idx < 26 && idy < 26){
            while(idx < 26 && countx[idx] == 0)
                idx++;
            while(idy < 26 && county[idy] == 0)
                idy++;
            if(idx >= 26)
                break;
            res += Math.abs(idx - idy);
            countx[idx]--;
            county[idy]--;
        }
        System.out.println(res);
    }
}
### 回答1: 好的,我来用中文回复这个链接:https://leetcode-cn.com/tag/dynamic-programming/ 这个链接是 LeetCode 上关于动态规划的题目集合。动态规划是一种常用的算法思想,可以用来解决很多实际问题,比如最长公共子序列、背包问题、最短路径等等。在 LeetCode 上,动态规划也是一个非常重要的题型,很多题目都需要用到动态规划的思想来解决。 这个链接里包含了很多关于动态规划的题目,按照难度从简单到困难排列。每个题目都有详细的题目描述、输入输出样例、题目解析和代码实现等内容,非常适合想要学习动态规划算法的人来练习和提高自己的能力。 总之,这个链接是一个非常好的学习动态规划算法的资源,建议大家多多利用。 ### 回答2: 动态规划是一种算法思想,通常用于优化具有重叠子问题和最优子结构性质的问题。由于其成熟的学理论和强大的实用效果,动态规划在计算机科学、学、经济学、管理学等领域均有重要应用。 在计算机科学领域,动态规划常用于解决最优化问题,如背包问题、图像处理、语音识别、自然语言处理等。同时,在计算机网络和分布式系统中,动态规划也广泛应用于各种优化算法中,如链路优化、路由算法、网络流量控制等。 对于算法领域的程序员而言,动态规划是一种必要的技能和知识点。在LeetCode这样的程序员平台上,题目分类和标签设置十分细致和方便,方便程序员查找并深入学习不同类型的算法。 LeetCode的动态规划标签下的题目涵盖了各种难度级别和场景的问题。从简单的斐波那契列、迷宫问题到可以用于实际应用的背包问题、最长公共子序列等,难度不断递进且话题丰富,有助于开发人员掌握动态规划的实际应用技能和抽象思维模式。 因此,深入LeetCode动态规划分类下的题目学习和练习,对于程序员的职业发展和技能提升有着重要的意义。 ### 回答3: 动态规划是一种常见的算法思想,它通过将问题拆分成子问题的方式进行求解。在LeetCode中,动态规划标签涵盖了众多经典和优美的算法问题,例如斐波那契列、矩阵链乘法、背包问题等。 动态规划的核心思想是“记忆化搜索”,即将中间状态保存下来,避免重复计算。通常情况下,我们会使用一张二维表来记录状态转移过程中的中间值,例如动态规划求解斐波那契列问题时,就可以定义一个二维组f[i][j],代表第i项斐波那契列中,第j个元素的值。 在LeetCode中,动态规划标签下有众多难度不同的问题。例如,经典的“爬楼梯”问题,要求我们计算到n级楼梯的方案。这个问题的解法非常简单,只需要维护一个长度为n的组,记录到达每一级楼梯的方案即可。类似的问题还有“零钱兑换”、“乘积最大子组”、“通配符匹配”等,它们都采用了类似的动态规划思想,通过拆分问题、保存中间状态来求解问题。 需要注意的是,动态规划算法并不是万能的,它虽然可以处理众多经典问题,但在某些场景下并不适用。例如,某些问题的状态转移过程比较复杂,或者状态转移方程中存在多个参,这些情况下使用动态规划算法可能会变得比较麻烦。此外,动态规划算法也存在一些常见误区,例如错用贪心思想、未考虑边界情况等。 总之,掌握动态规划算法对于LeetCode的学习和解题都非常重要。除了刷题以外,我们还可以通过阅读经典的动态规划书籍,例如《算法竞赛进阶指南》、《算法与据结构基础》等,来深入理解这种算法思想。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值