开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第22天,点击查看活动详情
6258. 数组中最长的方波
给你一个整数数组 nums 。如果 nums 的子序列满足下述条件,则认为该子序列是一个 方波 :
- 子序列的长度至少为
2,并且 - 将子序列从小到大排序 之后 ,除第一个元素外,每个元素都是前一个元素的 平方 。
返回 **nums **中 最长方波 的长度,如果不存在 方波 **则返回 **-1 。
子序列 也是一个数组,可以由另一个数组删除一些或不删除元素且不改变剩余元素的顺序得到。
示例 1 :
输入: nums = [4,3,6,16,8,2]
输出: 3
解释: 选出子序列 [4,16,2] 。排序后,得到 [2,4,16] 。
- 4 = 2 * 2.
- 16 = 4 * 4.
因此,[4,16,2] 是一个方波.
可以证明长度为 4 的子序列都不是方波。
示例 2 :
输入: nums = [2,3,5,6,7]
输出: -1
解释: nums 不存在方波,所以返回 -1 。
提示:
2 <= nums.length <= 1052 <= nums[i] <= 105
思路
对于这道题目,定义方波是由小到大的序列,很显然的可以想到,要先对数组进行升序排序,然后再寻找最长的方波。
一开始的思路是通过回溯的方法遍历所有的情况,但这种方法写出来会超时,对于超时的情况,有俩种解决方式,一种是继续优化边界条件,剪枝,减少无效的搜索,另一种方法是用空间换时间,将已计算的结果存起来,后续需要时不需要重复的计算,可通过记忆化搜索的方法解决。
在优化的过程中,突然想到可以使用动态规划的方式来解决该问题,对于每个元素,若可以和前面的元素组成方波,则该元素方波的长度等于前面元素方波的长度加一,同时定义一个变量用来存储整个数组中方波的最大值,将所有元素判断完毕后,即可得到最大长度的方波。
对于数组中相同的元素,进行重复的判断是没有必要的,故采用 set 将所有元素进行去重,使用不重复的数组计算方波可减少计算时间。
题解
class Solution {
public int longestSquareStreak(int[] nums) {
TreeSet<Integer> set = new TreeSet<>();
for(int num: nums) {
set.add(num);
}
nums = new int[set.size()];
int index = 0;
for(int key: set) {
nums[index++] = key;
}
int n = nums.length;
int[] dp = new int[n];
dp[0] = 1;
int max = 1;
for(int i = 1; i < n; i++) {
dp[i] = 1;
for(int j = 0; j < i && nums[i] >= nums[j] * nums[j]; j++) {
if(nums[i] == nums[j] * nums[j]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
max = Math.max(max, dp[i]);
}
}
}
return max == 1? -1: max;
}
}