leetcode2501. 数组中最长的方波

102 阅读2分钟

题目描述

给你一个整数数组 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 的子序列都不是方波。

暴力法思路

  1. 将数组排序 定义最大长为-1
  2. 外层循环控制起始数 curVal 内层循环根据起始数去寻找
  3. 如果找到则更新curVal 的值 并将当前的长度++
  4. 内部循环结束 将当前的长度与此时记录的最大长度取最大值

代码如下

/**
 * @param {number[]} nums
 * @return {number}
 */
var longestSquareStreak = function(nums) {
  nums.sort((a,b)=>a-b)
  let len = nums.length
  let max = -1
  for(let i = 0; i < len; i++) {
    let curLen = 1
    let curVal = nums[i]
    for(let j =i+1; j <len ; j++) {
      // 如果满足len++ val 变为 val*val
      if(nums[j] == curVal * curVal) {
        curLen++
        curVal = curVal * curVal
      }
    }
    // 如果大于2 则有 取最大值
    if(curLen >=2) {
      max = Math.max(curLen,max)
    }
  }
  return max
};

提交后发现超时,思考后发现优化点

优化思路

  1. 数组可以进行去重处理
  2. 因为数组是递增的 在本次循环可以记录一个临界值
  3. 因为 nums[i] 是一定会大于 nums[i-1] 的 那么在内部遍历时候 可以记录某个临界值nums[j]满足nums[j] 大于 nums[i]*nums[i] nums[j-1] 小于等于 nums[i]*nums[i]
  4. 当本次外部循环遍历结束后 下次循环便可以直接从索引j开始 因为前面的值都是不满足的

优化后代码

/**
 * @param {number[]} nums
 * @return {number}
 */
var longestSquareStreak = function(nums) {
  nums = [...new Set(nums)]
  nums.sort((a,b)=>a-b)
  let len = nums.length
  let max = -1
  // 减枝
  let preIndex = 1
  for(let i = 0; i < len; i++) {
    let curLen = 1
    let curVal = nums[i]
    for(let j = preIndex ; j <len ; j++) {
      if(nums[j - 1] <= nums[i] * nums[i] && nums[j] > nums[i] * nums[i]) {
        preIndex = j 
      }
      // 如果满足len++ val 变为 val*val
      if(nums[j] == curVal * curVal) {
        curLen++
        curVal = curVal * curVal
      }
    }
    // 如果大于2 则有 取最大值
    if(curLen >=2) {
      max = Math.max(curLen,max)
    }
  }
  return max
};

虽然最后勉强ac用时挺多,但自己思考做出来还是挺有成就感的