Given a string which contains only lowercase letters, remove duplicate letters so that every letter appear once and only once. You must make sure your result is the smallest in lexicographical order among all possible results.
Example:
Given "bcabc"
Return "abc"
Given "cbacdcbc"
Return "acdb"
// attempt: 1 -> does not return in smallest lexical-graphical order
#include<iostream>#include<string>#include<vector>#include<algorithm>#include<map>usingnamespace std;voidprint1d(vector<int> &nums) { for (auto i : nums) cout << i <<' '; cout << endl; }voidprintMap(map<char,int> &myMap) {for (auto i : myMap) { cout <<i.first <<" => "<<i.second << endl; }}map<char,int> mapAlpha() { map<char,int> alpha;for (int i =0; i <26; i++) {alpha.insert({ static_cast<char>('a'+ i),0 }); }return alpha;}stringremoveDuplicateLetters(string s) { map<char,int> alphaCount =mapAlpha(); //printMap(alphaCount);for (int i =0; i <s.size(); ++i) { // duplicate existsif (alphaCount.find(s.at(i))->second !=0) {s.erase(s.begin() + i); i--; } // unique letterelse {alphaCount.find(s.at(i))->second =1; } }return s;}intmain(){ string s ="aaacomn"; string result =removeDuplicateLetters(s); cout << result << endl;}
// attempt2:
Brainstorming:
For every duplicate, measure its displacement distance to every other non-duplicate element. Then add this elements together. So for every duplicate there will be a number associated with it. Finally, all duplicate positions will be erased from the string, except for the position with the minimum distance.
Really slow, and I am sure there is a better solution - but it's my current intuition.
Retrospect:
I will likely rewriting this entire program again from scratch. There are too many redudancies, and very difficult to read implementation. Functions are not reproducable, and I am pretty sure there is an entirely different, but better algorithm that is both simplier and more efficient. This was good practice, I suppose.
#include<iostream>#include<string>#include<vector>#include<algorithm>#include<math.h>#include<map>usingnamespace std;voidprint1d(vector<int> &nums) { for (auto i : nums) cout << i <<' '; cout << endl; }voidprintMap(map<char,int> &myMap) {for (auto i : myMap) { cout <<i.first <<" => "<<i.second << endl; }}voidprint2d(vector<vector<int>> &nums){for (int i =0; i <nums.size(); i++) {for (int j =0; j <nums.at(i).size(); j++) { cout <<nums.at(i).at(j) <<' '; } cout << endl; }}voidprintVectorMap(map<char,vector<int>> &myMap) {for (auto i : myMap) { cout <<i.first <<" => {";for (int j =0; j <i.second.size(); j++) { cout <<i.second.at(j) <<","; } cout <<"}"<< endl; }}map<char,vector<int>> mapAlpha() { string alphabet ="abcdefghijklmnopqrstuvwxyz"; map<char, vector<int>> alpha; vector<int> emptyVector;for (auto i : alphabet) {alpha.insert({ i, emptyVector }); }return alpha;}vector<int> findMinIndexPerUniqueCharacter(vector<vector<int>> *nums,map<char,vector<int>> &counts) { vector<int> removeTheseIndexPositions;int min_index; // remove min index location from map // print2d((*nums));for (int i =0; i < (*nums).size(); i++) { // find min index per characterif ((*nums).at(i).size() <1) removeTheseIndexPositions.push_back(-1); // -1 to designate no duplicateselse { min_index =min_element((*nums).at(i).begin(), (*nums).at(i).end()) - (*nums).at(i).begin();removeTheseIndexPositions.push_back(min_index); } }int counter =0; // iterate through map, to give us the final duplicates //print1d(removeTheseIndexPositions);for (std::map<char,vector<int>>::iterator it =counts.begin(); it !=counts.end(); ++it) {if (removeTheseIndexPositions.at(counter) ==-1) { counter++;continue; }else {it->second.erase(it->second.begin() +removeTheseIndexPositions.at(counter)); //printVectorMap(counts); counter++; } }removeTheseIndexPositions.clear();for (auto i : counts) {for (int j =0; j <i.second.size() &&i.second.size() >1; j++) {removeTheseIndexPositions.push_back(i.second.at(j)); } }print1d(removeTheseIndexPositions);return removeTheseIndexPositions;}vector<int> duplicatePositions(map<char,vector<int>> &counts,string s) { vector<char> duplicatesChars; vector<int> duplicatesPos; vector<int> nonDuplicatePos; // find the duplicated charactersfor (auto i : counts) {if (i.second.size() >1) {duplicatesChars.push_back(i.first); } } // link duplicated characters to the original stringfor (int i =0; i <s.size(); i++) {for (int j =0; j <duplicatesChars.size(); j++) {if (s.at(i) ==duplicatesChars.at(j)) {duplicatesPos.push_back(i); }elsenonDuplicatePos.push_back(i); } } // next we find the duplicate distance // every character has with it an associated distance // I will use an vector to fold these distances in respective order of the stringint distanceSum =0; // subset of distances per unique character vector<int> uniqueCharDistances; vector<vector<int>> distances;for (auto i : counts) { // > 1 to ignore it if character only appears oncefor (int k =0; k <i.second.size() &&i.second.size() >1; k++) {for (int j =0; j <nonDuplicatePos.size(); j++) { distanceSum +=abs(i.second.at(k) -nonDuplicatePos.at(j)); } // gone through the entire vector for duplicate characteruniqueCharDistances.push_back(distanceSum); distanceSum =0; } // look at next unique character in the mapdistances.push_back(uniqueCharDistances);uniqueCharDistances.clear(); } // I now have to choose the minimum per UNIQUE duplicate element, // but this minimum has to be mapped directly with its index location //printVectorMap(counts); //print2d(distances);returnfindMinIndexPerUniqueCharacter(&distances, counts);}vector<int> findDuplicates(string s) { map<char, vector<int>> alphaCount =mapAlpha();for (int i =0; i <s.size(); i++) { //count all positions for each charalphaCount.find(s.at(i))->second.push_back(i); }returnduplicatePositions(alphaCount, s);}stringremoveDuplicateLetters(string s) { vector<int> charsToRemove =findDuplicates(s);sort(charsToRemove.begin(),charsToRemove.end());for (int i =charsToRemove.size() -1; i >=0; i--) {s.erase(s.begin() +charsToRemove.at(i)); }return s;}intmain(){ string s ="ddddssssaaaaok"; string result =removeDuplicateLetters(s); cout << result << endl;}