leetcode/71-75

目录

253-会议室

279-完全平方数

283-移动0

287-寻找重复的数

297-二叉树的序列化和反序列化


253-会议室(..)

279-完全平方数

class Solution {
    public int numSquares(int n) {
        int[] f = new int[n+1];
        for(int i=1;i<=n;i++){
            int min = Integer.MAX_VALUE;
            for(int j=1;j*j<=i;j++){
                min = Math.min(min,f[i-j*j]);
            }
            f[i] = min + 1;
        }
        return f[n];
    }
}

283-移动0

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:

输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:

必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。

class Solution {
    public void moveZeroes(int[] nums) {
        if(nums==null||nums.length==0) return;
        //双指针,标记0的位置,用来交换
        int j =0;
        for(int i=0;i<nums.length;i++){
            //不等于0则j后移,直到当前位置nums[i]=0
            if(nums[i]!=0){
                //i,j不在同一位置时(i是一定大于或者等于j的)
                if(i!=j){
                    nums[j] = nums[i];
                    nums[i] = 0;
                }
                j++;
            }
        }
    }
}

287-寻找重复的数

给定一个包含 n + 1 个整数的数组 nums ,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。

假设 nums 只有 一个重复的整数 ,找出 这个重复的数 。

你设计的解决方案必须不修改数组 nums 且只用常量级 O(1) 的额外空间。

示例 1:

输入:nums = [1,3,4,2,2]
输出:2
示例 2:

输入:nums = [3,1,3,4,2]
输出:3

我们将:0 看作指针,指向 nums[0],而 nums[0] 也是指针,指向 nums[nums[0]].

如[1,3,1,2]:   0-->1-->3-->2-->1-->3-->2-->1-->3-->2....就形成了环

注意::这里之所以能够成环是因为“其数字都在 1 到 n 之间(包括 1 和 n)”,也就是说必定有重复的数

如果没有重复的数,如:数组 [1,4,3,2]  0-->1-->4-->null 就会超出界线

class Solution {
    public int findDuplicate(int[] nums) {
        int fast = 0;
        int slow = 0;
        //注意slow的写法,它走两步才是  slow = nums[nums[slow]];
        //也就是相当于fast走两步,slow走一步
        //slow = nums[slow];
        //fast = nums[nums[fast]];
        //注意如果这里写slow !=fast,就不能都把fast和slow放在0的位置
        //while(slow !=fast){
        while(true){
            slow = nums[slow];
            //环形链表中还需要判断nums[fast]是否为空
            fast = nums[nums[fast]];
            if(slow == fast) break;
        }
        slow = 0;
        while(slow!=fast){
            slow =  nums[slow];
            fast = nums[fast];
        }
        return slow;
    }
}

297-二叉树的序列化和反序列化

序列化是将一个数据结构或者对象转换为连续的比特位的操作,进而可以将转换后的数据存储在一个文件或者内存中,同时也可以通过网络传输到另一个计算机环境,采取相反方式重构得到原数据。

请设计一个算法来实现二叉树的序列化与反序列化。这里不限定你的序列 / 反序列化算法执行逻辑,你只需要保证一个二叉树可以被序列化为一个字符串并且将这个字符串反序列化为原始的树结构。

提示: 输入输出格式与 LeetCode 目前使用的方式一致,详情请参阅 LeetCode 序列化二叉树的格式。你并非必须采取这种方式,你也可以采用其他的方法解决这个问题。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        //层次遍历,依次增加节点即可

        //初始化可变字符串
        StringBuilder string = new StringBuilder();
        //注意::返回空字符串
        if(root==null) return "";
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while(!queue.isEmpty()){
            TreeNode tempNode = queue.poll();
            if(tempNode!=null){
                string.append(String.valueOf(tempNode.val));
                //不用判断是否为空
                //1 2 3 null null 4 5
                queue.offer(tempNode.left);
                queue.offer(tempNode.right);
            }else{
                string.append("null");
            }
            string.append(",");
        }
        return string.toString();
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if(data=="") return null;
        //分离字符
        String[] dataList = data.split(",");
        System.out.print(dataList[0]);
       TreeNode root = new TreeNode(Integer.parseInt(dataList[0]));
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        //下标
        int index = 1;
        //依次进队把节点连接成树
        //队列中依次进入的:根 左 右 左 右...,只需要依次进队,然后左,右连接即可
        while(!queue.isEmpty()){
            TreeNode node = queue.poll();
            //判断左节点
            if(!"null".equals(dataList[index])){
                node.left = new TreeNode(Integer.parseInt(dataList[index]));
                queue.offer(node.left);
            }
            index++;
            //判断右节点
            if(!"null".equals(dataList[index])){
                node.right = new TreeNode(Integer.parseInt(dataList[index]));
                queue.offer(node.right);
            }
            index++;
        }
        return root;
    }
}

// Your Codec object will be instantiated and called as such:
// Codec ser = new Codec();
// Codec deser = new Codec();
// TreeNode ans = deser.deserialize(ser.serialize(root));

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答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、付费专栏及课程。

余额充值