1346. 检查整数及其两倍数是否存在
给你一个整数数组 arr
,请你检查是否存在两个整数 N
和 M
,满足 N
是 M
的两倍(即,N = 2 * M
)。
更正式地,检查是否存在两个下标 i
和 j
满足:
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
//一共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
,请你根据下面的算法重新构造字符串:
- 从
s
中选出 最小 的字符,将它 接在 结果字符串的后面。 - 从
s
剩余字符中选出 最小 的字符,且该字符比上一个添加的字符大,将它 接在 结果字符串后面。 - 重复步骤 2 ,直到你没法从
s
中选择字符。 - 从
s
中选出 最大 的字符,将它 接在 结果字符串的后面。 - 从
s
剩余字符中选出 最大 的字符,且该字符比上一个添加的字符小,将它 接在 结果字符串后面。 - 重复步骤 5 ,直到你没法从
s
中选择字符。 - 重复步骤 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:
输入:root = [1,null,1,1,1,null,null,1,1,null,1,null,null,null,1,null,1]
输出:3
解释:蓝色节点为树中最长交错路径(右 -> 左 -> 右)。
示例 2:
输入: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;
}
}
}