Skip to content

Instantly share code, notes, and snippets.

@wilderfield
Last active October 21, 2023 00:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wilderfield/e306bd77b7477ddf948909d98b31c29b to your computer and use it in GitHub Desktop.
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.
#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