2021.8.9 每日一题
超级丑数 是一个正整数,并满足其所有质因数都出现在质数数组 primes 中。
给你一个整数 n 和一个整数数组 primes ,返回第 n 个 超级丑数 。
题目数据保证第 n 个 超级丑数 在 32-bit 带符号整数范围内。
示例 1:
输入:n = 12, primes = [2,7,13,19]
输出:32
解释:给定长度为 4 的质数数组 primes = [2,7,13,19],前 12 个超级丑数序列为:[1,2,4,7,8,13,14,16,19,26,28,32] 。
示例 2:
输入:n = 1, primes = [2,3,5]
输出:1
解释:1 不含质因数,因此它的所有质因数都在质数数组 primes = [2,3,5] 中。
提示:
1 <= n <= 106
1 <= primes.length <= 100
2 <= primes[i] <= 1000
题目数据 保证 primes[i] 是一个质数
primes 中的所有值都 互不相同 ,且按 递增顺序 排列
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/super-ugly-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
做过丑数一二,万万没想到还有个超级丑数
堆的做法,每次从最小堆堆顶取出最小数,然后和给定的表中元素相乘,得到新的超级丑数
注意得用long,因为堆中有的数可能会越界
class Solution {
public int nthSuperUglyNumber(int n, int[] primes) {
//昨晚看了一下,应该是动规
//所有质因数都出现在数组里,应该是用数组中的数动规
//刚开始数组中总共l+1个数,然后就是里面的数互相乘,得到下一个数
//其实和丑数2差不多,那应该怎么做呢
//dp[i][j]
//首先写个堆把,感觉堆比较好想
int l = primes.length;
PriorityQueue<Long> pq = new PriorityQueue<>();
//每次弹出堆顶的数,然后和primes中的数相乘,如果没有存在过,就加入堆
//用一个哈希表去重,防止重复
Set<Long> set = new HashSet<>();
set.add(1L);
pq.offer(1L);
for(int i = 1; i < n; i++){
//当前堆顶的数
long temp = pq.poll();
for(int base : primes){
long t = temp * base;
if(!set.contains(t)){
pq.offer(t);
set.add(t);
}
}
}
long res = pq.poll();
return (int)res;
}
}
动态规划
最后丑数序列中的数,都是每个primes中的数(加上1),不断相乘得到的
所以可以想到,用一个base数组,对应primes数组。例如,base[j]表示当前位置的质因数primes[j]可以乘的最小数
但是如果每次求这个数组中的最小数的话,肯定会超时
所以用一个dp数组,记录当前计算到的丑数
然后base中存放的是,可以乘的最小数在dp数组中对应的下标
再更新的时候,每次计算base数组中每一个位置对应的数dp[base[j]] * primes[j],得到当前质因数能计算得到的最小值,然后所有位置取最小值,就可以得到第i个丑数,将这个丑数放进dp数组中
同时注意:因为比如第一个例子中的,26这个数字,可以由2*13和13*2得到,所以要更新两个base中的位置
ps:10^6*100 我还以为会超时,结果能超几乎100。。
class Solution {
public int nthSuperUglyNumber(int n, int[] primes) {
//昨晚看了一下,应该是动规
//所有质因数都出现在数组里,应该是用数组中的数动规
//刚开始数组中总共l+1个数,然后就是里面的数互相乘,得到下一个数
//其实和丑数2差不多,那应该怎么做呢
//dp[i][j]
int l = primes.length;
//想想动规,每个数有l个数可以乘
//然后标记哪个数被乘过了,如果都被乘过了,那么就下一个数
//但是怎么取下一个数呢
//对于第一个例子,比如第一个数是1,那么它有l个数可以乘
//从小到大,得到第二个数是2,dp[1] = 1; dp[2] = 2;
//然后比较1*7和2 *2 ,得到第三个数是4
//然后比较1*7和4*2
//有了,就是对于primes中的每个数,都有一个当前的最小数,然后根据这个最小数,往后计算
//对应primes中每个位置的最小数
int[] base = new int[l];
//刚开始所有的最小数都为1
Arrays.fill(base, 1);
//记录当前丑数
int[] dp = new int[n + 1];
dp[1] = 1;
for(int i = 2; i <= n; i++){
//计算当前的超级丑数
int res = Integer.MAX_VALUE;
for(int j = 0; j < l; j++){
if(dp[base[j]] * primes[j] < res){
res = dp[base[j]] * primes[j];
}
}
//如果当前最小数是t位置取的,那么就把t位置的下标往后移一位
//但是因为会有重复的,所以需要判断
for(int j = 0; j < l; j++){
if(dp[base[j]] * primes[j] == res){
base[j]++;
}
}
dp[i] = res;
//System.out.println(res);
}
return dp[n];
}
}
2021.8.10 每日一题
如果一个数列 至少有三个元素 ,并且任意两个相邻元素之差相同,则称该数列为等差数列。
例如,[1,3,5,7,9]、[7,7,7,7] 和 [3,-1,-5,-9] 都是等差数列。
给你一个整数数组 nums ,返回数组 nums 中所有为等差数组的 子数组 个数。
子数组 是数组中的一个连续序列。
示例 1:
输入:nums = [1,2,3,4]
输出:3
解释:nums 中有三个子等差数组:[1, 2, 3]、[2, 3, 4] 和 [1,2,3,4] 自身。
示例 2:
输入:nums = [1]
输出:0
提示:
1 <= nums.length <= 5000
-1000 <= nums[i] <= 1000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/arithmetic-slices
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
判断之间的差值相等就OK
然后统计这个相等的次数,直到不相等时,得到了这个等差序列最长的长度。例如 1 2 3 4 5,得到了count = 3
因为这只是记录了1开头的等差数列的个数
当2开头,这个个数是2,;3开头是1;因此可以得到,当找到不相等时,可以通过(1+count)*count/2来求得这个序列的等差数列的个数,加到结果集中
class Solution {
public int numberOfArithmeticSlices(int[] nums) {
//记录每两个数之间的差值
int l = nums.length;
if(l < 3)
return 0;
int[] diff = new int[l - 1];
for(int i = 1; i < l; i++){
diff[i - 1] = nums[i] - nums[i - 1];
}
int count = 0;
int res = 0;
int pre = diff[0];
for(int i = 1; i < l - 1; i++){
if(diff[i] == pre){
count++;
}else{
count = (count + 1) * count / 2;
res += count;
pre = diff[i];
count = 0;
}
}
if(count != 0){
count = (count + 1) * count / 2;
res += count;
}
return res;
}
}
给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例 1:
输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
示例 2:
输入:numbers = [2,3,4], target = 6
输出:[1,3]
示例 3:
输入:numbers = [-1,0], target = -1
输出:[1,2]
提示:
2 <= numbers.length <= 3 * 104
-1000 <= numbers[i] <= 1000
numbers 按 递增顺序 排列
-1000 <= target <= 1000
仅存在一个有效答案
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum-ii-input-array-is-sorted
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
手贱,点开了一个学习的打开,又不想错过那个徽章,所以能做的话来做一下
class Solution {
public int[] twoSum(int[] numbers, int target) {
int l = numbers.length;
int left = 0;
int right = l - 1;
while(left < right){
while(numbers[left] + numbers[right] < target)
left++;
while(numbers[left] + numbers[right] > target)
right--;
if(numbers[left] + numbers[right] == target)
break;
}
return new int[]{left + 1, right + 1};
}
}