leetcode 402 321 316

402 移掉k个数字

结合官方题解以及 https://leetcode-cn.com/problems/create-maximum-number/solution/yi-zhao-chi-bian-li-kou-si-dao-ti-ma-ma-zai-ye-b-7/ 看下面的思路

算法的核心原理是贪心算法,可以思考一下当执行到删k-1步得到最小时值时,如何采取下一步策略能够得到删k的最优解,并利用替换的思想作证明
**具体为:**假设一个最优解删除的元素位置为 p 1 , p 2 , . . , p k − 1 , p k p_1,p_2,..,p_{k-1},p_k p1,p2,..,pk1,pk, 设删掉 p 1 , p 2 , . . , p k − 1 p_1,p_2,..,p_{k-1} p1,p2,..,pk1位置后的序列为x,则下一步a.删除x中第一个不符合升序的元素的前一个位置pos,b.若x中元素均为升序,则最后一个位置作为pos,无论是a还是b,一定是构成最优解的,也就是pos等于 p k p_k pk, 否则以pos替代 p k p_k pk就能得到一个更优解,这和假设中序列 p 1 , p 2 , . . , p k − 1 , p k p_1,p_2,..,p_{k-1},p_k p1,p2,..,pk1,pk构成最优矛盾。

c++代码:

//此算法的核心原理是贪心算法,可以思考一下当执行到删k-1步得到最小时值时,如何采取下一步策略能够得到删k的最优解,并利用替换证明
//贪心策略确实能够构成全局最优解

//先思考num中没有零时的情况
//若存在零,则以同样的逻辑处理,只是在输出时屏蔽前导0,具体可以看看官方的输出示例!
class Solution {
public:
    string removeKdigits(string num, int org_k) {
        vector<char> st; //利用vector模拟栈,方便取出元素
		int k = org_k; //为说明算法才写了这个变量,实际可以不需要
		//*************************************************************
		//此段为单调栈的写法,但未用到单调栈的性质
		//而是利用了贪心策略
        for (auto& digit: num) {
            while (k>0 && !st.empty() && st.back() > digit) {
                st.pop_back();
                --k;
            }
            st.push_back(digit);
        }
		//*************************************************************
		
		//为何不要担心栈为空还继续进行pop操作?
		//原因:
		// 由于每个元素都必须入栈,设num中的元素个数为 n ,由题意得 org_k<=n, 即 n - org_k >=0   
		// 另一方面,出栈次数为 org_k - k,故栈中保留的元素个数为 n - (org_k - k) = n-org_k+k >= k 
		// 因此不用担心会出现栈为空还继续进行pop操作
        for (; k > 0; --k) {
            st.pop_back();
        }
		
		//至此,栈中的元素一定就是我们需要的答案
		//但是结合输出示例可知,前导0无需显示,因此要跳过
		
		//下面分三种情况讨论看一下的输出代码:
		// 1. st 为空,即意味着org_k 等于 num.size(),依照题例,直接输出 "0"
		// 2. 存在前导0则直接跳过,若跳过后栈为空,输出的也是 "0"  若跳过后非空,则直接输出非空的结果
		// 3. 不存在前导0,则直接输出栈中元素作为结果
		
        string ans = "";
        bool isLeadingZero = true;
        for (auto& digit: st) {
            if (isLeadingZero && digit == '0') {
                continue;
            }
            isLeadingZero = false;
            ans += digit;//这行代码表示的是字符串的拼接,不要理解成值的相加
        }
        return ans == "" ? "0" : ans;
    }
};

316

//理解402再做此题
class Solution {
public:
    string removeDuplicateLetters(string s) {
        unordered_map<char,int> count;
        vector<bool> is_in_st(26,false);

        //统计每个字母出现的次数
        for(auto & ch : s){
            ++count[ch];
        }

        //下面代码与402十分类似

        //计算重复元素的个数,即需要移除的元素个数
        // int k = s.size() - count.size(); //测试用
        string st;
        for(auto & ch : s){
            if(is_in_st[ch-'a'] == false){
                while(!st.empty() && st.back() > ch && count[ st.back() ] > 1){
                    --count[ st.back() ]; //不要漏掉这个!
                    // --k; //测试用
                    is_in_st[st.back()-'a'] = false;
                    st.pop_back();   
                }
                st.push_back(ch);
                is_in_st[ch-'a'] = true;
            }else{
                --count[ ch ]; 
                // --k; //测试用
            }
            
        }

        // // 测试用 
        // string ans1(st.begin(),st.end());
        // cout<<ans1<<k;

        return st;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值