leetcode做题记录

1346. 检查整数及其两倍数是否存在

给你一个整数数组 arr,请你检查是否存在两个整数 NM,满足 NM 的两倍(即,N = 2 * M)。

更正式地,检查是否存在两个下标 ij 满足:

  • i != j
  • 0 <= i, j < arr.length
  • arr[i] == 2 * arr[j]

示例 1:

输入:arr = [10,2,5,3]
输出:true
解释:N = 10 是 M = 5 的两倍,即 10 = 2 * 5 。

示例 2:

输入:arr = [7,1,14,11]
输出:true
解释:N = 14 是 M = 7 的两倍,即 14 = 2 * 7 。

示例 3:

输入:arr = [3,1,7,11]
输出:false
解释:在该情况下不存在 N 和 M 满足 N = 2 * M 。

提示:

  • 2 <= arr.length <= 500
  • -10^3 <= arr[i] <= 10^3
//暴力穷举或者hash 这里使用hashset存储值就可以
class Solution {
    public boolean checkIfExist(int[] arr) {
          HashSet<Integer>set=new HashSet<>();
          for(int num:arr){
              if(set.contains(num*2)||(num%2==0&&set.contains(num/2))){  //判断set中是否存在当前值的二倍或一半,只有偶数需要判断,奇数一定不存在
                  return true;
              }
              set.add(num);
          }
          return false;
    }
}
1359. 有效的快递序列数目

给你 n 笔订单,每笔订单都需要快递服务。

请你统计所有有效的 收件/配送 序列的数目,确保第 i 个物品的配送服务 delivery(i) 总是在其收件服务 pickup(i) 之后。

由于答案可能很大,请返回答案对 10^9 + 7 取余的结果。

示例 1:

输入:n = 1
输出:1
解释:只有一种序列 (P1, D1),物品 1 的配送服务(D1)在物品 1 的收件服务(P1)后。

示例 2:

输入:n = 2
输出:6
解释:所有可能的序列包括:
(P1,P2,D1,D2),(P1,P2,D2,D1),(P1,D1,P2,D2),(P2,P1,D1,D2),(P2,P1,D2,D1) 和 (P2,D2,P1,D1)。
(P1,D2,P2,D1) 是一个无效的序列,因为物品 2 的收件服务(P2)不应在物品 2 的配送服务(D2)之后。

示例 3:

输入:n = 3
输出:90

提示:

  • 1 <= n <= 500

image-20220923153458150

image-20220923153533720

//一共2n个物品对2n个物品进行排列的个数是(2n)!,
//考虑顺序的问题,对于每个组都确定了位置这样可以看出是一个分组,在这个分组内每一组的物品可以选择前面的位置和后面的位置,一共2的i次方种情况,这些情况中只有每一组都是送在前,收在后才能成立。所以要除以2的i次方

class Solution {
   final int mod=1000000007;
    long  res=1;
    public int countOrders(int n) {     //(2n)!/2的i次方把偶数项提出来
         for(int i=1;i<=2*n;i++){
             if(i%2==1){       //是奇数直接乘
              res=res*i%mod;
             }
             else{
                 res=res*i/2%mod; //是偶数除以2
             }
         }
         return (int)res%mod;
    }
}
1360. 日期之间隔几天

请你编写一个程序来计算两个日期之间隔了多少天。

日期以字符串形式给出,格式为 YYYY-MM-DD,如示例所示。

示例 1:

输入:date1 = "2019-06-29", date2 = "2019-06-30"
输出:1

示例 2:

输入:date1 = "2020-01-15", date2 = "2019-12-31"
输出:15

提示:

  • 给定的日期是 1971 年到 2100 年之间的有效日期。
//模拟题 建立months数组记录每个月的天数 写一个函数判断是否是闰年。

class Solution {  final int[]months={0,31,28,31,30,31,30,31,31,30,31,30,31};
    public int daysBetweenDates(String date1, String date2) {
       
         return Math.abs(getSum(date1)-getSum(date2));
    }
      int getYear(int year){
          if(year%4==0&&year%100!=0||year%400==0){
              return 1;
          }
          else{
              return 0;
          }
         }
         int getDay(int year,int month){
             if(month!=2){
                 return months[month];
             }
             else{
                 return 28+getYear(year);
             }
         }
         int getSum(String date){            //和1970 1.1这个基准日期算值,之后两个值进行计算
             String[]str=date.split("-");
             int year=Integer.parseInt(str[0]);
             int month=Integer.parseInt(str[1]);
             int day=Integer.parseInt(str[2]);
             int res=0;
             for(int i=1971;i<year;i++){
                 res+=365+getYear(i);
             }
             for(int i=1;i<month;i++){
                 res+=getDay(year,i);
             }
             return res+day;
         }
}
1370. 上升下降字符串

给你一个字符串 s ,请你根据下面的算法重新构造字符串:

  1. s 中选出 最小 的字符,将它 接在 结果字符串的后面。
  2. s 剩余字符中选出 最小 的字符,且该字符比上一个添加的字符大,将它 接在 结果字符串后面。
  3. 重复步骤 2 ,直到你没法从 s 中选择字符。
  4. s 中选出 最大 的字符,将它 接在 结果字符串的后面。
  5. s 剩余字符中选出 最大 的字符,且该字符比上一个添加的字符小,将它 接在 结果字符串后面。
  6. 重复步骤 5 ,直到你没法从 s 中选择字符。
  7. 重复步骤 1 到 6 ,直到 s 中所有字符都已经被选过。

在任何一步中,如果最小或者最大字符不止一个 ,你可以选择其中任意一个,并将其添加到结果字符串。

请你返回将 s 中字符重新排序后的 结果字符串

示例 1:

输入:s = "aaaabbbbcccc"
输出:"abccbaabccba"
解释:第一轮的步骤 1,2,3 后,结果字符串为 result = "abc"
第一轮的步骤 4,5,6 后,结果字符串为 result = "abccba"
第一轮结束,现在 s = "aabbcc" ,我们再次回到步骤 1
第二轮的步骤 1,2,3 后,结果字符串为 result = "abccbaabc"
第二轮的步骤 4,5,6 后,结果字符串为 result = "abccbaabccba"

示例 2:

输入:s = "rat"
输出:"art"
解释:单词 "rat" 在上述算法重排序以后变成 "art"

示例 3:

输入:s = "leetcode"
输出:"cdelotee"

示例 4:

输入:s = "ggggggg"
输出:"ggggggg"

示例 5:

输入:s = "spo"
输出:"ops"

提示:

  • 1 <= s.length <= 500
  • s 只包含小写英文字母。
class Solution {
    public String sortString(String s) {
         int[]hash=new int[26];       //只有小写字母,用数组当作hash表
         for(char cha:s.toCharArray()){
             hash[cha-'a']++;      //计算每个字母个数
         }
         StringBuilder str=new StringBuilder();
         while(str.length()<s.length()){
             for(int i=0;i<26;i++){       //从左到右,因为每次i都会++所以只会加入更大的字母
                 if(hash[i]>0){
                     str.append((char)('a'+i));
                     hash[i]--;
                 }
             }
            for(int i=25;i>=0;i--){    //从左到右不能走了就从右到左走,通过str的长度控制while循环的结束
                 if(hash[i]>0){
                     str.append((char)('a'+i));
                     hash[i]--;
                 }
             } 
         }
         return str.toString();
    }
}
1371. 每个元音包含偶数次的最长子字符串

给你一个字符串 s ,请你返回满足以下条件的最长子字符串的长度:每个元音字母,即 ‘a’,‘e’,‘i’,‘o’,‘u’ ,在子字符串中都恰好出现了偶数次。

示例 1:

输入:s = "eleetminicoworoep"
输出:13
解释:最长子字符串是 "leetminicowor" ,它包含 e,i,o 各 2 个,以及 0 个 a,u 。

示例 2:

输入:s = "leetcodeisgreat"
输出:5
解释:最长子字符串是 "leetc" ,其中包含 2 个 e 。

示例 3:

输入:s = "bcbcbc"
输出:6
解释:这个示例中,字符串 "bcbcbc" 本身就是最长的,因为所有的元音 a,e,i,o,u 都出现了 0 次。

提示:

  • 1 <= s.length <= 5 x 10^5
  • s 只包含小写英文字母。
//为什么想到用位01表示是因为字符出现次数只有两个状态奇数和偶数所以可以用01表示,aeiou表示5个字母的奇偶就用一个五位的二进制数00000表示,同时二进制数有对应的10进制数,一数双用。5位的二进制数有32种状态定义一个大小为32的数组
class Solution {
    public int findTheLongestSubstring(String s) {
         int[]state=new int[32];
         Arrays.fill(state,-2);
         String str="aeiou";       //当移位的时候需要获取字母对应的数这里定义一个字符串通过indexOf获取值,也可以用一个hashmap
         int max=0;
         int pre=0;      //pre是一个状态的转移 最开始是00000,在过程中不断地更新
         state[0]=-1;        //赋值成-1是因为当i=0如果不是aeiou此时aeiou的数量都是偶数字符串长度为1,0-(-1)=1;00000这种情况因为初始就全是偶数所以计算会比其他情况duo1,所以干脆加上1              
         for(int i=0;i<s.length();i++){       //遍历每一个字母
            int k=str.indexOf(s.charAt(i));      //获取它的位置,如果不存在返回-1
            if(k!=-1){                       //只有是aeiou才会更新状态
                  pre^=1<<k;          
            }
           
             if(state[pre]==-2){                //说明第一次到这个状态,记录这个状态第一次出现的index
                 state[pre]=i;
             }
             else{
                  max=Math.max(max,i-state[pre]);   //说明之前出现过这个状态进行更新,这里的原理是如果0-x的状态和0-y的状态相同说明x+1-y的五个字母的个数都是偶数,因为只有这种情况状态才不会改变。
         }
         return max;
    }
}
1372. 二叉树中的最长交错路径

给你一棵以 root 为根的二叉树,二叉树中的交错路径定义如下:

  • 选择二叉树中 任意 节点和一个方向(左或者右)。
  • 如果前进方向为右,那么移动到当前节点的的右子节点,否则移动到它的左子节点。
  • 改变前进方向:左变右或者右变左。
  • 重复第二步和第三步,直到你在树中无法继续移动。

交错路径的长度定义为:访问过的节点数目 - 1(单个节点的路径长度为 0 )。

请你返回给定树中最长 交错路径 的长度。

示例 1:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-spTbXooa-1663933019046)(https://cdn.jsdelivr.net/gh/happyprograming-haha/picgo/img/202209231921376.png)]

输入:root = [1,null,1,1,1,null,null,1,1,null,1,null,null,null,1,null,1]
输出:3
解释:蓝色节点为树中最长交错路径(右 -> 左 -> 右)。

示例 2:

img

输入:root = [1,1,1,null,1,null,null,1,1,null,1]
输出:4
解释:蓝色节点为树中最长交错路径(左 -> 右 -> 左 -> 右)。

示例 3:

输入:root = [1]
输出:0
class Solution {
    int res=0;
    public int longestZigZag(TreeNode root) {
          dfs(root,-1);          //-1不会被用到,没有影响
          return res;
    }                                       //dfs求以某个方向进入某个点的交错路径的长度
    public int dfs(TreeNode node,int d){       //进行遍历通过d来传递信息是从哪个方向遍历到了该点
        if(node==null){         
            return 0;
        }
        int left=dfs(node.left,0);         //left代表向左子树走,0代表左
        int right=dfs(node.right,1);
        res=Math.max(res,Math.max(left,right));
        if(d==0){            //说明当前点是父节点的左子树,之后要往右走
            return right+1;
        }
        else{
            return left+1;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值