I was trying out leetcode's Steps to Make Array Non-decreasing
As per the challenge's description:
You are given a 0-indexed integer array nums. In one step, remove all elements nums[i] where nums[i - 1] > nums[i] for all 0 < i < nums.length.
Return the number of steps performed until nums becomes a non-decreasing array.
Example 1:
Input: nums = [5,3,4,4,7,3,6,11,8,5,11] Output: 3 Explanation: The following are the steps performed:
- Step 1: [5,3,4,4,7,3,6,11,8,5,11] becomes [5,4,4,7,6,11,11]
- Step 2: [5,4,4,7,6,11,11] becomes [5,4,7,11,11]
- Step 3: [5,4,7,11,11] becomes [5,7,11,11] [5,7,11,11] is a non-decreasing array. Therefore, we return 3.
Constraints:
- 1 <= nums.length <= 1e5
- 1 <= nums[i] <= 1e9
Even though it doesn't mention any Big O constraint with regards to memory overheads, I am trying to build a solution that runs in O(n) time complexity along with O(1) memory overhead.
So far here is my solution in Java:
class Solution { private static void swap(int[] arr, int i, int ni) { int temp = arr[i]; arr[i] = arr[ni]; arr[ni] = temp; } public int totalSteps(int[] nums) { // Taking care of constraints given in challenge if (nums.length == 0 || nums.length == 1 || nums.length > Math.pow(10, 5)) { return 0; } // if array of size 2, O(1) check steps if (nums.length == 2) return nums[0] > nums[1] ? 1 : 0; // how many items removed in one full loop cycle int totalRemovedInACompleteLoop = 0; int steps = 0; for (int i = nums.length; i >= 1; i--) { // PS: this one is a temporary fix, refactor code for better approach // resolve resetting i at end // to re run a loop without going out of bound index if (i == nums.length) i -= 1; // -- temporary - to refactor--// // skip if already removed if (nums[i] == -1) continue; if (nums[i - 1] == -1) { // swap by moving removed (-1) nb to right swap(nums, i, i - 1); continue; } if (nums[i - 1] > nums[i]) { nums[i] = -1;// mark as removed ++totalRemovedInACompleteLoop;// increment counter } // Done or need to reloop? if (i == 1 && totalRemovedInACompleteLoop > 0) { i = nums.length; ++steps; totalRemovedInACompleteLoop = 0; } } return steps; } }
My solution so far passes 83/87 tests, until It reaches a test where the nums
array's size is \$10^5\$. When the array is of that size I get "Time Limit Exceeded". (PS: I had similar issues while trying leetcode's First missing Positive)
Note:
- This code while it works, will be refactored later on once i know which approach to follow for O(n) speed.
- I am aware that so far this solution's time complexity is \$O(n^2)+\$ and not \$O(n)\$
- When an item is removed it gets marked as "-1", I am modifying inputs of array in place.
- I could have used some DS to help (like stack, list etc..) and write another solution ( I saw several solutions posted there do that). But I want to make it work with O(1) memory overhead.
My question is: Can the approach I am following so far be done in O(n) time if ones insists on going with O(1) memory overhead? if yes, what algorithms should I read about and follow through to modify my code, and/or what are your suggestions? (The point here is that I am trying to expand my knowledge in areas where it lacks)
Example and output of this code so far:
int[] nums = new int[]{5, 3, 4, 4, 7, 3, 6, 11, 8, 5, 11}; //expected 3 Step 1: ie when for loop cycle finishes and before relooping --> array [5, -1, 4, 4, 7, -1, 6, 11, -1, -1, 11] // ie [5,4,4,7,6,11,11] Step 2: ie when for loop cycle finishes and before relooping --> array [5, -1, -1, 4, 7, -1, -1, 11, 11, -1, -1] //ie [5,4,7,11,11] Step 3: ie when for loop cycle finishes and before relooping --> array [5, -1, -1, -1, 7, 11, -1, -1, 11, -1, -1] // ie [5,7,11,11] > Final array [5, 7, -1, -1, -1, 11, 11, -1, -1, -1, -1] > Done in 3 Steps.