力扣打卡(1):每日亿题:初遇动态规划。

18 篇文章 0 订阅
16 篇文章 0 订阅

9.25lc

今日随计刷题:
每日抑题~~~~

动态规划 : 空间换时间

思考步骤

1.dp数组 以及下标的含义

2.递归公式

3.dp数组进行初始化

4.遍历顺序

5.是在不对 打印数组进行观察、

1143. 最长公共子序列 - 力扣(LeetCode) (leetcode-cn.com)

首先,区分两个概念:子序列可以是不连续的;子数组(子字符串)需要是连续的;
另外,动态规划也是有套路的:

  • 单个数组或者字符串要用动态规划时,可以把动态规划 dp[i] 定义为 nums[0:i] 中想要求的结果;
  • 当两个数组或者字符串要用动态规划时,可以把动态规划定义成两维的 dp[i][j],其含义是在 A[0:i] 与 B[0:j] 之间匹配得到的想要的结果。

1.状态定义
比如对于本题而言,可以定义 dp[i][j] 表示 text1[0:i-1] 和 text2[0:j-1] 的最长公共子序列。 (注:text1[0:i-1] 表示的是 text1 的 第 0 个元素到第 i - 1 个元素,两端都包含)
之所以 dp[i][j] 的定义不是 text1[0:i] 和 text2[0:j] ,是为了方便当 i = 0 或者 j = 0 的时候,dp[i][j]表示的为空字符串和另外一个字符串的匹配,这样 dp[i][j] 可以初始化为 0.

2.状态转移方程
知道状态定义之后,我们开始写状态转移方程。

  • 当 text1[i - 1] == text2[j - 1] 时,说明两个子字符串的最后一位相等,所以最长公共子序列又增加了 1,所以 dp[i][j] = dp[i - 1][j - 1] + 1;举个例子,比如对于 ac 和 bc 而言,他们的最长公共子序列的长度等于 a 和 b 的最长公共子序列长度 0 + 1 = 1。
  • 当 text1[i - 1] != text2[j - 1] 时,说明两个子字符串的最后一位不相等,那么此时的状态 dp[i][j] 应该是 dp[i - 1][j] 和 dp[i][j - 1] 的最大值。
    • 举个例子,比如对于 “ace “和” bc” 而言,他们的最长公共子序列的长度等于
    • ① ace 和 b 的最长公共子序列长度0
    • ② ac 和 bc 的最长公共子序列长度1 的最大值,即 1。
      综上状态转移方程为:

dp[i][j] = dp[i - 1][j - 1] + 1dp[i][j]=dp[i−1][j−1]+1, 当 text1[i - 1] == text2[j - 1];text1[i−1]==text2[j−1];
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])dp[i][j]=max(dp[i−1][j],dp[i][j−1]), 当 text1[i - 1] != text2[j - 1]text1[i−1]!=text2[j−1]

3.状态的初始化
初始化就是要看当 i = 0 与 j = 0 时, dp[i][j] 应该取值为多少。

  • 当 i = 0 时,dp[0][j] 表示的是 text1text1 中取空字符串 跟 text2text2 的最长公共子序列,结果肯定为 0.
  • 当 j = 0 时,dp[i][0] 表示的是 text2text2 中取空字符串 跟 text1text1 的最长公共子序列,结果肯定为 0.
    综上,当 i = 0 或者 j = 0 时,dp[i][j] 初始化为 0.

4.遍历方向与范围
由于 dp[i][j] 依赖与 dp[i - 1][j - 1] , dp[i - 1][j], dp[i][j - 1],所以 ii 和 jj 的遍历顺序肯定是从小到大的。
另外,由于当 ii 和 jj 取值为 0 的时候,dp[i][j] = 0,而 dp 数组本身初始化就是为 0,所以,直接让 ii 和 jj 从 1 开始遍历。遍历的结束应该是字符串的长度为 len(text1)len(text1) 和 len(text2)len(text2)。

5.最终返回结果
由于 dp[i][j] 的含义是 text1[0:i-1] 和 text2[0:j-1] 的最长公共子序列。我们最终希望求的是 text1 和 text2 的最长公共子序列。所以需要返回的结果是 i = len(text1) 并且 j = len(text2) 时的 dp[len(text1)][len(text2)]。


class Solution {
    public int longestCommonSubsequence(String text1, String text2) {
      int len1=text1.length();
      int len2=text2.length();
       //二维的数组 表示的 两个字符串 相同字符的长度问题:
      int[][] dp=new int[len1+1][len2+1];
        //进行初始化:表示的 0 和某一个字符串的比较就 == 0;
      dp[0][0] =0;
     
      for(int i=1;i<=len1;i++){
          for(int j=1;j<=len2;j++){  
            if(text1.charAt(i-1)==text2.charAt(j-1)){
                //相等  长度+1
                dp[i][j]=dp[i-1][j-1]+1;
            }
            else{
                //不等  去两个字符串中连续长度 最大的!
             dp[i][j]=Math.max(dp[i][j-1],dp[i-1][j]);
            }
          }
      }
      return dp[len1][len2];
    }
}
583. 两个字符串的删除操作 - 力扣(LeetCode) (leetcode-cn.com)

上一题思路的一样:

class Solution {
    public int minDistance(String word1, String word2) {
      int len1=word1.length();
      int len2=word2.length();
      int[][] dp=new int[len1+1][len2+1];
      dp[0][0] =0;
     
      for(int i=1;i<=len1;i++){
          for(int j=1;j<=len2;j++){  
            if(word1.charAt(i-1)==word2.charAt(j-1)){
                dp[i][j]=dp[i-1][j-1]+1;
            }
            else{
             dp[i][j]=Math.max(dp[i][j-1],dp[i-1][j]);
            }
          }
      }
      return len2+len1 - 2*dp[len1][len2];
    }
}
617. 合并二叉树 - 力扣(LeetCode) (leetcode-cn.com)

: dfs:

  • 注意 递归的条件。
  • 读懂题意;不要因为简单 导致边界问题:
class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
      TreeNode cur= new TreeNode(0);

      if(root1 ==null){
          return root2;
      }
      if(root2 ==null){
          return root1;
      }
      //这里的 cur.left; 应该注意返回值:
       // 注意 node 节点的 写法!
      cur=new TreeNode(root1.val+root2.val);
        //注意 递归的返回值 !
      cur.left=mergeTrees(root1.left,root2.left);
      cur.right= mergeTrees(root1.right,root2.right);
    return cur;
    }
}

:为了降低空间复杂度 直接原来的树上改:

时间复杂度:O*(min(m,*n))

class Solution {
    public TreeNode mergeTrees(TreeNode root1, TreeNode root2) {
      TreeNode cur= new TreeNode(0);

      if(root1 ==null){
          return root2;
      }
      if(root2 ==null){
          return root1;
      }
      //这里的 cur.left; 应该主义返回值:
       root1.val+=root2.val;
        root1.left=mergeTrees(root1.left,root2.left);
      root1.right= mergeTrees(root1.right,root2.right);
    return root1;
    }
}
116. 填充每个节点的下一个右侧节点指针 - 力扣(LeetCode) (leetcode-cn.com)

:思路: 二叉树的宽度遍历:

  • 注意 判断每层最后一个的条件:
  • queue.peek() 和 queue.elment()的区别;
/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;

    public Node() {}
    
    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, Node _left, Node _right, Node _next) {
        val = _val;
        left = _left;
        right = _right;
        next = _next;
    }
};
*/

class Solution {
    public Node connect(Node root) {
    Queue<Node> queue =new LinkedList<>();
    queue.add(root); 
   if(root ==null) return root;
  
    while( !queue.isEmpty()){
       int size=queue.size();

        for(int i=0; i<size;i++){
            Node cur =queue.poll();
            // i =0 开始
            if(i<size-1){
                //peek() 指向队列头 没有值为 null;
             cur.next =queue.peek();

            }
             if(cur.left != null){
            queue.add(cur.left);
        }
         if(cur.right != null){
            queue.add(cur.right);
        }

        }
       
       }
       return root;
    }  
        
    }

2.: 省空间的方法:

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;
    public Node next;

    public Node() {}
    
    public Node(int _val) {
        val = _val;
    }

    public Node(int _val, Node _left, Node _right, Node _next) {
        val = _val;
        left = _left;
        right = _right;
        next = _next;
    }
};
*/
class Solution {
    public Node connect(Node root) {
   
   if(root ==null) return root;
  
     Node pre=root;
     while(pre.left != null){
   Node cur =pre;

    while(cur !=null){
        cur.left.next=cur.right;

        if(cur.next != null){
            cur.right.next=cur.next.left;
        }
        cur=cur.next;
    }
   pre=pre.left;
     }

     return root;
    }  
        
}
695. 岛屿的最大面积 - 力扣(LeetCode) (leetcode-cn.com)

:dfs

: 沉没岛屿思想: 将每次找的的岛屿进行 置0 即 沉没 。保证了以后的遍历不会出错:

:常用的控制 方向的 方法:

  • 方向数组

    • int[] up ={0,0,1,-1};
      int[] left={1,-1,0,0};
      
    • 直接初始化指针 移动: +1,-1;

class Solution {
    public int maxAreaOfIsland(int[][] grid) {
    int res=0;
   for(int i=0; i<grid.length;i++){
       for(int j=0;j<grid[0].length;j++){

        if(grid[i][j]==1){
          res =Math.max(res,dfs(i,j,grid));
        }
       }
      
   }
 return res;
    }

    

    public int dfs(int i,int j, int[][] grid){
//边界条件: 出界 或者 无岛屿  直接 返回0
        if(i<0||i>=grid.length ||j<0||j>= grid[0].length || grid[i][j] ==0){
            return 0;
        }
// 沉没岛屿
        grid[i][j] =0;
        int num=1;
        num+= dfs(i+1,j,grid);
        num+= dfs(i-1,j,grid);
        num+= dfs(i,j+1,grid);
        num+= dfs(i,j-1,grid);

        return num;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
题目描述: 给你两个版本号 version1 和 version2 ,请你比较它们。 版本号由一个或多个修订号组成,各修订号由一个 '.' 连接。每个修订号由多位数字组成,可能包含前导零。每个版本号至少包含一个字符。修订号从左到右编号,下标从0开始,最左边的修订号下标为0 ,下一个修订号下标为1,以此类推。例如,2.5.33 和 0.1 都是有效的版本号。 比较版本号时,请按从左到右的顺序依次比较它们的修订号。比较修订号时,只需比较忽略任何前导零后的整数值。也就是说,修订号1和修订号001相等。如果版本号没有指定某个下标处的修订号,则该修订号视为0。例如,版本1.0 小于版本1.1,因为它们下标为0的修订号相同,而下标为1的修订号分别为0和1,0 < 1。 返回规则如下: 如果 version1 > version2 返回 1, 如果 version1 < version2 返回 -1, 否则返回 0。 示例 1: 输入:version1 = "1.01", version2 = "1.001" 输出:0 解释:忽略前导零,"01" 和 "001" 都表示相同的整数 "1" 示例 2: 输入:version1 = "1.0", version2 = "1.0.0" 输出:0 解释:version1 没有指定下标为 2 的修订号,即视为 "0" 示例 3: 输入:version1 = "0.1", version2 = "1.1" 输出:-1 解释:version1 中下标为 0 的修订号是 0,version2 中下标为 0 的修订号是 1 。0 < 1,所以 version1 < version2 示例 4: 输入:version1 = "1.0.1", version2 = "1" 输出:1 示例 5: 输入:version1 = "7.5.2.4", version2 = "7.5.3" 输出:-1 提示: 1 <= version1.length, version2.length <= 500 version1 和 version2 仅包含数字和 '.' version1 和 version2 都是 有效版本号

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值