- https://leetcode.com/problems/remove-k-digits
string removeKdigits(string num, int k) {
// 使剩余数字串最小,需要栈中留下递增序列 <=> 找下一个更小的数
// 在此基础上,考虑限制条件:
// 当栈内个数+剩余可压栈个数>needed时才可pop(),栈内个数<needed时才可push()
const int N = num.size(), needed = N - k;
string s;
for (int i = 0; i < N; i++) {
while (!s.empty() && num[i] < s.back() && s.size() + (N - i) > needed) { // [i,N)是剩余可压栈的数字
s.pop_back();
}
if (s.size() < needed) s.push_back(num[i]);
}
// 删除开头的0
int pos = 0;
while (pos < s.size() && s[pos] == '0') pos++;
return pos < s.size() ? s.substr(pos) : "0";
}
vector<int> maxNumber(vector<int>& nums1, vector<int>& nums2, int k) {
// 一个数组取i个数拼成最大数,另一个数组取k-i个数拼成最大数,将两个最大数归并成两数组的最大数。
// 0<=i<=M, 0<=k-i<=N => 0<=i<=M, k-N<=i<=k => max(0,k-N)<=i<=min(k,M)
vector<int> ans;
const int M = nums1.size(), N = nums2.size();
int minI = max(0, k - N), maxI = min(k, M);
for (int i = minI; i <= maxI; i++) {
auto maxNum1 = maxNumber(nums1, i);
auto maxNum2 = maxNumber(nums2, k - i);
auto merged = merge(maxNum1, maxNum2);
if (isDigitallyGreaterOrEqual(merged, 0, ans, 0)) ans = merged;
}
return ans;
}
// 单数字数组保持组内顺序取k个数字,拼成最大的数
vector<int> maxNumber(vector<int>& nums, int k) {
// 拼成最大的数:栈中留下的是递减序列 <=> 找下一个更大的数
// 取k个数:当栈内数字个数+剩余可压栈个数>k时才可pop(),栈内数字个数<k时才可push()
const int N = nums.size();
vector<int> stk;
for (int i = 0; i < N; i++) {
while (!stk.empty() && nums[i] > stk.back()
&& stk.size() + (N - i) > k) { // [i,N)是剩余可压栈的数字
stk.pop_back();
}
if (stk.size() < k) stk.push_back(nums[i]);
}
return stk;
}
vector<int> merge(vector<int> &nums1, vector<int> &nums2) {
vector<int> ans;
int size = nums1.size() + nums2.size();
for (int i = 0, j = 0, k = 0; k < size; k++) {
if (isDigitallyGreaterOrEqual(nums1, i, nums2, j)) ans.push_back(nums1[i++]);
else ans.push_back(nums2[j++]);
}
return ans;
}
// 按位比较nums1[i1..]和nums2[i2..]的大小
bool isDigitallyGreaterOrEqual(vector<int> &nums1, int i1, vector<int> &nums2, int i2) {
while (i1 < nums1.size() && i2 < nums2.size() && nums1[i1] == nums2[i2]) {
i1++;
i2++;
}
return (i2 == nums2.size() || (i1 < nums1.size() && nums1[i1] > nums2[i2]));
}
string removeDuplicateLetters(string s) {
// 要使剩余串的字典序最小<=>递增栈<=>找下一个更小的数
// 限制条件:1.已入栈的不再选择 2.某字母有富余时才可pop()
vector<int> cnt(128, 0); // 各字母计数
for (char c : s) cnt[c]++;
vector<bool> picked(128, false);
string stk;
for (char c : s) {
cnt[c]--;
if (picked[c]) continue; // 条件1
while (!stk.empty() && c < stk.back()
&& cnt[stk.back()] > 0) { // 条件2
int top = stk.back(); stk.pop_back();
picked[top] = false;
}
stk.push_back(c);
picked[c] = true;
}
return stk;
}