题目来源:. - 力扣(LeetCode)
题目思路分析
题目:摆动序列(Wiggle Subsequence)
给定一个整数序列 nums
,找到具有最大长度的摆动序列。摆动序列的定义是:如果序列中的数字不是全部递增也不是全部递减,那么该序列就是摆动序列。一个空的或只包含一个元素的序列也被视为摆动序列。
思路:
- 边界情况处理:
- 如果序列长度为1,直接返回1,因为单个元素本身就是一个摆动序列。
- 如果序列长度为2,检查两个元素是否相等,如果相等返回1(因为两个相同的元素不构成摆动序列),否则返回2(两个不同元素自然构成一个摆动序列)。
- 跳过连续相同元素:
- 使用一个指针
k
来跳过序列开头所有连续相同的元素。这一步是为了避免在序列开始部分浪费计算资源,并且可以确定序列是否完全由相同元素组成。
- 使用一个指针
- 核心逻辑:
- 遍历剩余序列,检查每个元素是否构成摆动(即当前元素与前一个元素和后一个元素的关系)。
- 如果当前元素与前后元素构成摆动,则摆动序列长度加1。
- 如果当前元素与前一个元素相等或者与前一个元素和后一个元素的关系不满足摆动条件,则尝试跳过后续不满足条件的元素,直到找到一个新的摆动点。
- 返回结果:
- 遍历结束后,返回计算得到的摆动序列的最大长度。
代码:
class Solution {
public: int wiggleMaxLength(vector<int>& nums) { if (nums.size() == 1) { return 1; // 单个元素是摆动序列 } if (nums.size() == 2) { if (nums[0] == nums[1]) { return 1; // 两个相同元素不构成摆动序列 } return 2; // 两个不同元素构成摆动序列 } int k = 0; // 跳过开头所有连续相同的元素 while (k < nums.size() - 1 && nums[k] == nums[k + 1]) { k++; } if (k == nums.size() - 1) { return 1; // 序列完全由相同元素组成 } int ans = 2; // 初始化摆动序列长度为2(因为至少有两个不同的元素) for (int i = k + 1; i < nums.size() - 1; i++) { // 检查当前元素是否构成摆动 if ((nums[i] - nums[i - 1]) * (nums[i + 1] - nums[i]) < 0) { ans++; // 构成摆动,长度加1 continue; } // 尝试跳过不满足条件的元素 int k_temp = i - 1; while (i < nums.size() - 1 && (nums[i] - nums[k_temp]) * (nums[i + 1] - nums[i]) >= 0) { i++; } if (i < nums.size() - 1) { ans++; // 找到新的摆动点,长度加1 } } return ans; }
};
知识点摘要
- 边界情况处理:在处理数组、链表等数据结构时,考虑边界情况(如空数组、单个元素数组)非常重要。
- 滑动窗口/指针技术:通过指针或索引来遍历数组,跳过不必要的计算,提高算法效率。
- 数学判断:利用乘法判断数字间的大小关系,从而确定是否构成摆动。
摆动序列问题是一个经典的算法问题,它考察了对数组遍历、边界情况处理以及数学判断的综合应用能力。通过本题,我们可以学习到如何在遍历数组时高效地跳过不必要的元素,以及如何运用数学方法(如乘法判断)来简化问题。此外,本题也强调了边界情况处理的重要性,无论是单个元素数组还是两个元素的数组,都需要特殊处理。通过不断优化代码,我们可以提高算法的效率,从而更好地解决实际问题。