LeetCode每日一题--402. 移掉K位数字(贪心 单调栈)

题目:跳转至 402. 移掉K位数字
给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。
注意:

  • num 的长度小于 10002 且 ≥ k。
  • num 不会包含任何前导零。

示例 1 :

输入: num = “1432219”, k = 3
输出: “1219”
解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。
示例 2 :
输入: num = “10200”, k = 1
输出: “200”
解释: 移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。
示例 3 :
输入: num = “10”, k = 2
输出: “0”
解释: 从原数字移除所有的数字,剩余为空就是0。

class Solution {
public:
    string removeKdigits(string num, int k) {

    }
};

思路:
因为要移除k个数字后剩下的数字最小,数字首位的影响最大。所以,直接就能想到从前往后遍历,如果前一位数字比他后一位更大,就把前一个数字移除,直到移除k个,得出结果。
问题在于,比如4531去除3个,从首位开始算,4<5略过,接下来5>3,5要去掉,然后要比较的不是3>1而是4>3,那比较过的值应该被存储下来,有需要时先进后出的跟其余值比较,用栈就比较明显了。

class Solution {
public:
    string removeKdigits(string num, int k) {
        stack<int> st;
        string res;
        int len=num.length();
        if(len==0)
            return res;
        else if(len==1 && k==0)
            return num;
        else if(len==1 && k==1)
            return "0";
        bool isSame=true;
        for(int i=1;i<len;++i){  //如果全相等
            if(num[i]!=num[0])
                isSame=false;
        }
        if(isSame==true){
            num.erase(0,k);
            return num;
        }
        int i=1,count=0;
        while(count<k && i<=len-count){  //删除k个数,注意循环条件
            st.push(i-1);
            int temp=st.top();
            if(num[temp]>num[i]){
                num.erase(temp,1);
                st.pop();
                ++count;
                --i;  //因为从num中去除了一个数
            }
            ++i;
        }
        i=0;
        while(num[i]=='0')  //排除首位0
            num.erase(i,1);
        if(count<k)
            num.erase(num.length()-k+count);
        if(num.length()==0)
            num="0";
        return num;
    }
};

问题很多emmmm,结构也有点乱提交后有很多没想到的状况。比如相等的数去除,所有值都是升序排列,极端条件下值是空还是0这些都没考虑到,东拼西凑,还有点其他问题。
放弃挣扎,看题解,大佬就都很厉害。

class Solution {
public:
    string removeKdigits(string num, int k) {
        vector<char> stk;
        for (auto& digit: num) {  //没减满k个数时,一边存前一个数的值,一边比较
            while (stk.size() > 0 && stk.back() > digit && k) {
                stk.pop_back();
                k -= 1;
            }
            stk.push_back(digit);
        }
        for (; k > 0; --k)  //考虑上面没有去掉k接下来都是升序排列的情况,去除后面的值
            stk.pop_back();
        string ans = "";
        bool isLeadingZero = true;
        for (auto& digit: stk) {  //去0
            if (isLeadingZero && digit == '0') {
                continue;
            }
            isLeadingZero = false;
            ans += digit;
        }
        return ans == "" ? "0" : ans;
    }
};

比较起来,写法上最大的不同点是我只用栈来存储第一步比较时候的值,而实际上可以把所有值都丢进去。最关键的,先想明白可能的情况再开始写代码。

你可能感兴趣的:(leetcode每日一题,c++,leetcode)