Last active
October 21, 2023 00:46
-
-
Save wilderfield/e306bd77b7477ddf948909d98b31c29b to your computer and use it in GitHub Desktop.
Return the minimum number of elements to be removed to make a given array of numbers sorted.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <vector> | |
#include <iostream> | |
#include <limits.h> | |
#include <algorithm> | |
using namespace std; | |
// Let dp(i,j) = minimum number of elements excluded from nums[0:i] inclusive to keep it sorted, | |
// given nums[j] is already included and must be the maximum element | |
int dp(vector<int>& nums, int i, int j, vector<vector<int>>& memo) { | |
if (memo[i][j] == -1) { | |
// base case | |
if (i == 0) { | |
memo[i][j] = 0; | |
} | |
// If nums[i] is less than or equal to nums[j], the two values maintain a sorted order | |
// then we have two choices, and we pick the minimum | |
else if (nums[i] <= nums[j]) { | |
int includeOption = dp(nums, i-1, i, memo); | |
int excludeOption = dp(nums, i-1, j, memo) + 1; | |
memo[i][j] = min(includeOption, excludeOption); | |
} | |
// If nums[i] is greater than nums[j], we can't include it in a sorted array that also includes nums[j] | |
else { | |
int excludeOption = dp(nums, i-1, j, memo) + 1; | |
memo[i][j] = excludeOption; | |
} | |
} | |
return memo[i][j]; | |
} | |
int topDown(vector<int>& numbers) { | |
if (numbers.size() < 2) return 0; | |
// Create a new array {-INF, array, +INF} | |
// This will involve O(n) for copy | |
vector<int> nums = {INT_MIN}; | |
nums.insert(nums.end(), numbers.begin(), numbers.end()); | |
nums.push_back(INT_MAX); | |
int n = nums.size(); | |
vector<vector<int>> memo(n, vector<int>(n, -1)); | |
return dp(nums, n-2, n-1, memo); | |
} | |
int bottomUp(vector<int>& numbers) { | |
if (numbers.size() < 2) return 0; | |
// Create a new array {-INF, array, +INF} | |
// This will involve O(n) for copy | |
vector<int> nums = {INT_MIN}; | |
nums.insert(nums.end(), numbers.begin(), numbers.end()); | |
nums.push_back(INT_MAX); | |
int n = nums.size(); | |
// Initialize dp table, this is O(n^2) | |
vector<vector<int>> dp(n, vector<int>(n, 0)); | |
// Implement recurrence relationship, this is O(n^2) | |
for (int i = 1; i < (n-1); i++) { | |
for (int j = i+1; j < n; j++) { | |
if (nums[i] <= nums[j]) { | |
int includeOption = dp[i-1][i]; | |
int excludeOption = dp[i-1][j] + 1; | |
dp[i][j] = min(includeOption, excludeOption); // nums[i] may or may not be included in any sorted array that includes nums[j] | |
} | |
else { | |
int excludeOption = dp[i-1][j] + 1; | |
dp[i][j] = excludeOption; // nums[i] is excluded from any sorted array that includes nums[j] | |
} | |
} | |
} | |
return dp[n-2][n-1]; | |
} | |
vector<int> bottomUpGetRemoved(vector<int>& numbers) { | |
if (numbers.size() < 2) return {}; | |
// Create a new array {-INF, array, +INF} | |
vector<int> nums = {INT_MIN}; | |
nums.insert(nums.end(), numbers.begin(), numbers.end()); | |
nums.push_back(INT_MAX); | |
int n = nums.size(); | |
// Initialize dp table | |
vector<vector<int>> dp(n, vector<int>(n, 0)); | |
// Initialize array to track removed elements | |
vector<vector<bool>> removed(n, vector<bool>(n, false)); | |
// Implement recurrence relationship | |
for (int i = 1; i < (n-1); i++) { | |
for (int j = i+1; j < n; j++) { | |
if (nums[i] <= nums[j]) { | |
int includeOption = dp[i-1][i]; | |
int excludeOption = dp[i-1][j] + 1; | |
if (includeOption < excludeOption) { | |
dp[i][j] = includeOption; | |
} else { | |
dp[i][j] = excludeOption; | |
removed[i][j] = true; // Mark nums[i] for removal in this path | |
} | |
} | |
else { | |
int excludeOption = dp[i-1][j] + 1; | |
dp[i][j] = excludeOption; | |
removed[i][j] = true; // Mark nums[i] for removal in this path | |
} | |
} | |
} | |
// Trace back the removed elements | |
vector<int> result; | |
int i = n-2, j = n-1; | |
while (i > 0) { | |
if (!removed[i][j]) { | |
j = i; | |
} | |
else { | |
result.push_back(nums[i]); | |
} | |
i--; | |
} | |
return result; | |
} | |
// O(N) space solution | |
int bottomUpOptimized(vector<int>& numbers) { | |
if (numbers.size() < 2) return {}; | |
// Create a new array {-INF, array, +INF} | |
vector<int> nums = {INT_MIN}; | |
nums.insert(nums.end(), numbers.begin(), numbers.end()); | |
nums.push_back(INT_MAX); | |
int n = nums.size(); | |
// Initialize dp table | |
vector<int> dp(n, 0); | |
// Implement recurrence relationship | |
for (int i = 1; i < (n-1); i++) { | |
for (int j = i+1; j < n; j++) { | |
if (nums[i] <= nums[j]) { | |
int includeOption = dp[i]; | |
int excludeOption = dp[j] + 1; | |
dp[j] = min(includeOption, excludeOption); | |
} | |
else { | |
int excludeOption = dp[j] + 1; | |
dp[j] = excludeOption; | |
} | |
} | |
} | |
return dp[n-1]; | |
} | |
int main() { | |
vector<int> numbers = {1, 20, 3, 40, 4}; | |
int resultTopDown = topDown(numbers); | |
cout << "ResultTopDown: " << resultTopDown << endl; | |
int resultBottomUp = bottomUp(numbers); | |
cout << "ResultBottomUp: " << resultBottomUp << endl; | |
int resultBottomUpOptimized = bottomUpOptimized(numbers); | |
cout << "ResultBottomUpOptimized: " << resultBottomUpOptimized << endl; | |
auto res = bottomUpGetRemoved(numbers); | |
cout << "Elements to be removed: "; | |
for (auto& el : res) cout << el << ", "; | |
cout << endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment