Before attempting this problem, you should be comfortable with:
Arrays - Understanding how to iterate through arrays and access elements by index
Comparison Operators - Using comparison operators to check relationships between adjacent elements
1. Two Pass
Intuition
An array is monotonic if it is entirely non-decreasing or entirely non-increasing. We can check each condition separately. First, scan to see if every element is greater than or equal to the previous one. If this holds, the array is monotonically increasing. If not, scan again to check if every element is less than or equal to the previous one. If either condition is satisfied, the array is monotonic.
Algorithm
Assume the array is increasing. Iterate through and check if nums[i] < nums[i - 1] for any i. If found, the array is not increasing.
If the array passed the increasing check, return true.
Otherwise, assume the array is decreasing. Iterate through and check if nums[i] > nums[i - 1] for any i. If found, the array is not decreasing.
Return whether the array passed the decreasing check.
classSolution:defisMonotonic(self, nums: List[int])->bool:
n =len(nums)
increase =Truefor i inrange(1, n):if nums[i]< nums[i -1]:
increase =Falsebreakif increase:returnTrue
decrease =Truefor i inrange(1, n):if nums[i]> nums[i -1]:
decrease =Falsebreakreturn decrease
publicclassSolution{publicbooleanisMonotonic(int[] nums){int n = nums.length;boolean increase =true;for(int i =1; i < n; i++){if(nums[i]< nums[i -1]){
increase =false;break;}}if(increase){returntrue;}boolean decrease =true;for(int i =1; i < n; i++){if(nums[i]> nums[i -1]){
decrease =false;break;}}return decrease;}}
classSolution{public:boolisMonotonic(vector<int>& nums){int n = nums.size();bool increase =true;for(int i =1; i < n;++i){if(nums[i]< nums[i -1]){
increase =false;break;}}if(increase){returntrue;}bool decrease =true;for(int i =1; i < n;++i){if(nums[i]> nums[i -1]){
decrease =false;break;}}return decrease;}};
classSolution{/**
* @param {number[]} nums
* @return {boolean}
*/isMonotonic(nums){const n = nums.length;let increase =true;for(let i =1; i < n; i++){if(nums[i]< nums[i -1]){
increase =false;break;}}if(increase){returntrue;}let decrease =true;for(let i =1; i < n; i++){if(nums[i]> nums[i -1]){
decrease =false;break;}}return decrease;}}
publicclassSolution{publicboolIsMonotonic(int[] nums){int n = nums.Length;bool increase =true;for(int i =1; i < n; i++){if(nums[i]< nums[i -1]){
increase =false;break;}}if(increase){returntrue;}bool decrease =true;for(int i =1; i < n; i++){if(nums[i]> nums[i -1]){
decrease =false;break;}}return decrease;}}
funcisMonotonic(nums []int)bool{
n :=len(nums)
increase :=truefor i :=1; i < n; i++{if nums[i]< nums[i-1]{
increase =falsebreak}}if increase {returntrue}
decrease :=truefor i :=1; i < n; i++{if nums[i]> nums[i-1]{
decrease =falsebreak}}return decrease
}
class Solution {funisMonotonic(nums: IntArray): Boolean {val n = nums.size
var increase =truefor(i in1 until n){if(nums[i]< nums[i -1]){
increase =falsebreak}}if(increase){returntrue}var decrease =truefor(i in1 until n){if(nums[i]> nums[i -1]){
decrease =falsebreak}}return decrease
}}
classSolution{funcisMonotonic(_ nums:[Int])->Bool{let n = nums.count
var increase =truefor i in1..<n {if nums[i]< nums[i -1]{
increase =falsebreak}}if increase {returntrue}var decrease =truefor i in1..<n {if nums[i]> nums[i -1]{
decrease =falsebreak}}return decrease
}}
Time & Space Complexity
Time complexity: O(n)
Space complexity: O(1)
2. One Pass - I
Intuition
We can determine the expected direction by comparing the first and last elements. If the first element is less than or equal to the last, the array should be non-decreasing. Otherwise, it should be non-increasing. With the direction determined upfront, a single pass can verify whether all consecutive pairs follow the expected pattern.
Algorithm
Compare nums[0] and nums[n - 1] to determine the expected direction.
If nums[0] <= nums[n - 1], the array should be non-decreasing:
Iterate through and return false if any nums[i] < nums[i - 1].
Otherwise, the array should be non-increasing:
Iterate through and return false if any nums[i] > nums[i - 1].
classSolution:defisMonotonic(self, nums: List[int])->bool:
n =len(nums)if nums[0]<= nums[-1]:for i inrange(1, n):if nums[i]< nums[i -1]:returnFalsereturnTrueelse:for i inrange(1, n):if nums[i]> nums[i -1]:returnFalsereturnTrue
publicclassSolution{publicbooleanisMonotonic(int[] nums){int n = nums.length;if(nums[0]<= nums[n -1]){for(int i =1; i < n; i++){if(nums[i]< nums[i -1]){returnfalse;}}returntrue;}else{for(int i =1; i < n; i++){if(nums[i]> nums[i -1]){returnfalse;}}returntrue;}}}
classSolution{public:boolisMonotonic(vector<int>& nums){int n = nums.size();if(nums[0]<= nums[n -1]){for(int i =1; i < n;++i){if(nums[i]< nums[i -1]){returnfalse;}}returntrue;}else{for(int i =1; i < n;++i){if(nums[i]> nums[i -1]){returnfalse;}}returntrue;}}};
classSolution{/**
* @param {number[]} nums
* @return {boolean}
*/isMonotonic(nums){const n = nums.length;if(nums[0]<= nums[n -1]){for(let i =1; i < n; i++){if(nums[i]< nums[i -1]){returnfalse;}}returntrue;}else{for(let i =1; i < n; i++){if(nums[i]> nums[i -1]){returnfalse;}}returntrue;}}}
publicclassSolution{publicboolIsMonotonic(int[] nums){int n = nums.Length;if(nums[0]<= nums[n -1]){for(int i =1; i < n; i++){if(nums[i]< nums[i -1]){returnfalse;}}returntrue;}else{for(int i =1; i < n; i++){if(nums[i]> nums[i -1]){returnfalse;}}returntrue;}}}
funcisMonotonic(nums []int)bool{
n :=len(nums)if nums[0]<= nums[n-1]{for i :=1; i < n; i++{if nums[i]< nums[i-1]{returnfalse}}returntrue}else{for i :=1; i < n; i++{if nums[i]> nums[i-1]{returnfalse}}returntrue}}
class Solution {funisMonotonic(nums: IntArray): Boolean {val n = nums.size
if(nums[0]<= nums[n -1]){for(i in1 until n){if(nums[i]< nums[i -1]){returnfalse}}returntrue}else{for(i in1 until n){if(nums[i]> nums[i -1]){returnfalse}}returntrue}}}
classSolution{funcisMonotonic(_ nums:[Int])->Bool{let n = nums.count
if nums[0]<= nums[n -1]{for i in1..<n {if nums[i]< nums[i -1]{returnfalse}}returntrue}else{for i in1..<n {if nums[i]> nums[i -1]{returnfalse}}returntrue}}}
Time & Space Complexity
Time complexity: O(n)
Space complexity: O(1)
3. One Pass - II
Intuition
Rather than deciding the direction upfront, we can track both possibilities simultaneously. We maintain two flags: one for whether the array could still be non-decreasing, and one for whether it could still be non-increasing. As we scan, any violation disqualifies that direction. At the end, if at least one flag remains true, the array is monotonic.
Algorithm
Initialize two boolean flags: increase = true and decrease = true.
Iterate through consecutive pairs (nums[i], nums[i + 1]):
A monotonic array allows equal consecutive elements (non-decreasing or non-increasing). Using strict comparisons like nums[i] > nums[i-1] instead of nums[i] >= nums[i-1] incorrectly rejects arrays like [1, 2, 2, 3] as non-monotonic. The condition should check for <= (non-decreasing) or >= (non-increasing) to properly handle equal adjacent values.
Checking Only One Direction
Arrays that are constant (all elements equal) are both non-decreasing and non-increasing. Returning false early when detecting a violation in one direction without checking the other leads to incorrect results. The array [5, 5, 5] should return true, but checking only for strictly increasing or strictly decreasing patterns would fail this case.