给你两个非负整数low和high,请你返回low和high之间(包含二者)奇数的数目
0 <= low <= high <= 10^9
输入:low = 3,high = 7
输出: 3
解释:3到7之间的奇数有3,5,7共3个。
思路无非两种,一,直接模拟,二,寻找规律。
不假思索的模拟方法为:分出四类,low high组合,奇偶,奇奇,偶偶,偶奇,即可完成代码。在不需要花太多时间的第一题如果你没思路,那么完全可以这样做,代码量也不大。
第二种方法就是在上一种思路上再推一步,我们直接固定下区间,分别获取到从0开始分别到low和high的范围内的所有奇数个数,再两者相减,即可得到我们的目标值。
以上述示例说明:0-3的奇数个数为3 / 2 + 1= 2 ,0-7的奇数个数为7/2 + 1 = 4,加不加1取决于高位这个数是否为奇数,若为奇数则加1,不是则不加。注意包含high和low本身的数,因此实际上我们相当于漏掉了low这个值的奇偶性,因此再加上一个low % 2即可。写入代码你会发现实际上会将low%2约掉,也就是说low和high之间的奇数总数跟low的奇偶没有关系。因此最终优化代码如下。
class Solution {
public int countOdds(int low,int high) {
int Hcount = high / 2 + high % 2;
// int Lcount = low / 2 + low % 2;
int Lcount = low / 2 + low % 2;
// return Hcount - Lcount;
return Hcount - Lcount;
}
}
给你一个整数数组arr,请你返回和为奇数的子数组数目。
答案比较大,因此请你返回将结果对10^9+7取余的结果。
1 <= arr.length <= 10^5
1 <= arr[i] <= 100
输入: arr = [1,3,5]
输出: 4
解释:子数组为[[1],[3],[5],[1,3],[1,5],[3,5],[1,3,5]]共7个,
其和为1,3,5,4,6,8,9,
奇数包括1,3,5,9
共4个因此返回4.
class Solution {
public int numOfSubarrays(int[] arr) {
final int VAL = 1000000007;
int res = 0;
int[][] dp = new int[arr.length][2];
// base case
if (arr[0] % 2 == 1) {
dp[0][0] = 1;
} else {
dp[0][1] = 1;
}
// 状态转移
for (int i = 1; i < arr.length; i++) {
if (arr[i] % 2 == 0) {
dp[i][0] = dp[i - 1][0];
dp[i][1] = dp[i - 1][1] + 1;
} else {
dp[i][0] = dp[i - 1][1] + 1;
dp[i][1] = dp[i - 1][0];
}
}
// 结果
for (int j = 0; j < arr.length; j++) {
res += dp[j][0];
res %= VAL;
}
return res;
}
}
给你一个字符串s,一个分割被称为好分割的定义是:当它满足将s分为两个字符串p和q,连起来等于s,且p和q中不同字符的数目相同。
请你返回s中好分割的数目。
输入:s = “aacaba”
输出:2
解释:aac aba和aaca,ba两种分法满足好分割的要求。返回2
将字符串分为两部分,分别统计两部分的不同字母的数量,然后分割线从左边开始,找到好分割点则ans++即可。
class Solution {
public int numSplits(String s) {
int res = 0;
int lCount = 0,rCount = 0;
// 初始化左右两边的数组,数组索引对应具体字母,数组值对应字母出现次数。
int[] left = new int[26];
int[] right = new int[26];
// 分割线从左边开始,默认所有元素都在右边
for (int i = 0; i < s.length(); i++) {
int index = s.charAt(i) - 'a';
if (right[index] == 0) {
rCount++;
}
right[index]++;
}
// 开始移动分割线,每次移动一个元素到左边,先更新left数组,再更新lCount,再更新right数组,再更新rCount,最后再判断是否满足条件。
for (int j = 0; j < s.length(); j++) {
int index1 = s.charAt(j) - 'a';
if (left[index1] == 0) {
lCount++;
}
left[index1]++;
right[index1]--;
if (right[index1] == 0) {
rCount--;
}
if (lCount == Rcount) {
res++;
}
}
return res;
}
}
给你一个整数数组target和一个数组initial,initial数组与target数组有同样的维度,且一开始全部为0。
请你返回从initial到target的最少操作次数,每次操作需遵循以下规则:
在initial中选择任意子数组,并将子数组的每个元素+1。
答案保证在32位有符号整数以内。
输入: target = [1,2,3,2,1]
输出: 3
解释:从[0,0,0,0,0] -> [1,1,1,1,1] ->[1,2,2,2,1] ->[1,2,3,2,1] 共3次。
本题可以是一个波峰问题的原型题目,比如示例,给的就是一个山峰,从1爬山到3再下山到1,因为你需要从0开始加,且每次只能加1,那么思路就显而易见了,计算那个爬山或者下山的过程即可。我们以爬山为例进行代码实现即可。
class Solution {
public int minNumOperations(int[] target) {
// 题目未限定target的长度,因此需要特数情况处理,注意细节
if (target.length == 0 || target == null) {
return 0;
}
int res = target[0];
for (int i = 1; i < target.length; i++) {
res += Math.max(target[i] - target[i - 1], 0);
}
return res;
}
}