3637. 三段式数组 I
解法一
思路和算法
数组 $\textit{nums}$ 的长度是 $n$。最直观的思路是遍历 $0 < p < q < n - 1$ 的所有下标对 $(p, q)$,判断是否同时满足三段式数组的全部条件。
-
下标范围 $[0, p]$ 严格递增。
-
下标范围 $[p, q]$ 严格递减。
-
下标范围 $[q, n - 1]$ 严格递增。
当遇到满足全部条件的下标对 $(p, q)$ 时,返回 $\text{true}$。如果不存在满足全部条件的下标对 $(p, q)$,返回 $\text{false}$。
代码
###Java
class Solution {
public boolean isTrionic(int[] nums) {
int n = nums.length;
for (int p = 1; p < n - 2; p++) {
if (!isMonotonicInRange(nums, 0, p, 1)) {
continue;
}
for (int q = p + 1; q < n - 1; q++) {
if (isMonotonicInRange(nums, p, q, -1) && isMonotonicInRange(nums, q, n - 1, 1)) {
return true;
}
}
}
return false;
}
public boolean isMonotonicInRange(int[] nums, int start, int end, int direction) {
for (int i = start; i < end; i++) {
if ((nums[i + 1] - nums[i]) * direction <= 0) {
return false;
}
}
return true;
}
}
###C#
public class Solution {
public bool IsTrionic(int[] nums) {
int n = nums.Length;
for (int p = 1; p < n - 2; p++) {
if (!IsMonotonicInRange(nums, 0, p, 1)) {
continue;
}
for (int q = p + 1; q < n - 1; q++) {
if (IsMonotonicInRange(nums, p, q, -1) && IsMonotonicInRange(nums, q, n - 1, 1)) {
return true;
}
}
}
return false;
}
public bool IsMonotonicInRange(int[] nums, int start, int end, int direction) {
for (int i = start; i < end; i++) {
if ((nums[i + 1] - nums[i]) * direction <= 0) {
return false;
}
}
return true;
}
}
复杂度分析
-
时间复杂度:$O(n^3)$,其中 $n$ 是数组 $\textit{nums}$ 的长度。需要遍历的下标对数量是 $O(n^2)$,每个下标对判断是否符合三段式数组的全部条件的时间是 $O(n)$,因此时间复杂度是 $O(n^3)$。
-
空间复杂度:$O(1)$。
解法二
思路和算法
可以遍历数组 $\textit{nums}$ 一次,判断是否符合三段式的条件。
三个子数组的单调性必须依次满足严格单调递增、严格单调递减、严格单调递增。首个子数组的起始下标是 $0$,从起始下标向右遍历,遍历过程中执行如下操作。
-
由于三个子数组都满足严格单调递增或严格单调递减,因此不允许出现相邻元素相等的情况。如果遇到相邻元素相等的情况,则一定不符合三段式的条件。
-
如果遍历到数组 $\textit{nums}$ 的末尾或者遇到相邻元素的单调性与当前子数组的单调性条件相反的情况(已经排除相邻元素相等的情况),则可以确定当前子数组的结束下标。将当前子数组的结束下标作为下一个子数组的起始下标,继续遍历下一个子数组。
当数组 $\textit{nums}$ 可以恰好分成三个子数组且依次满足严格单调递增、严格单调递减、严格单调递增时,返回 $\text{true}$,否则返回 $\text{false}$。
代码
###Java
class Solution {
public boolean isTrionic(int[] nums) {
int n = nums.length;
int index = 0;
for (int i = 0, direction = 1; i < 3; i++, direction *= -1) {
index = findMonotonicRangeEnd(nums, index, direction);
if (index < 0) {
return false;
}
}
return index == n - 1;
}
public int findMonotonicRangeEnd(int[] nums, int start, int direction) {
int n = nums.length;
int end = -1;
for (int i = start; i < n && end < 0; i++) {
if (i < n - 1 && nums[i + 1] == nums[i]) {
return -1;
}
if (i == n - 1 || (nums[i + 1] - nums[i]) * direction < 0) {
end = i;
}
}
return end > start ? end : -1;
}
}
###C#
public class Solution {
public bool IsTrionic(int[] nums) {
int n = nums.Length;
int index = 0;
for (int i = 0, direction = 1; i < 3; i++, direction *= -1) {
index = FindMonotonicRangeEnd(nums, index, direction);
if (index < 0) {
return false;
}
}
return index == n - 1;
}
public int FindMonotonicRangeEnd(int[] nums, int start, int direction) {
int n = nums.Length;
int end = -1;
for (int i = start; i < n && end < 0; i++) {
if (i < n - 1 && nums[i + 1] == nums[i]) {
return -1;
}
if (i == n - 1 || (nums[i + 1] - nums[i]) * direction < 0) {
end = i;
}
}
return end > start ? end : -1;
}
}
复杂度分析
-
时间复杂度:$O(n)$,其中 $n$ 是数组 $\textit{nums}$ 的长度。最多需要遍历数组一次。
-
空间复杂度:$O(1)$。