算法:字符串组成的数组拼接后字典序最小的结果

题目描述

给定一个由字符串组成的数组strs,必须把所有的字符串拼接起来,返回所有拼接结果中,字典序最小的结果。

字典序定义:Java中字符串的排序方式,比如 “abc” 和 “bce”相比,“abc” 第一位a的ASCII码小于 “bce” 第一位b的ASCII码,所以 “abc” < “bce”,所以“abc”的字典序更小。对于位数不等的字符串,“abc” 和 “be”,从各自的第一位开始比较,“abc”的a小于“be”的b,所以“abc” < “be”。

class Solution {
    


public:
    std::string lowestString(std::vector<std::string> strs){
        
    }
};

思路

暴力

strs中所有字符串全排列,返回所有可能的结果

class Solution {
    static std::vector<std::string> removeIndexString(std::vector<std::string> arr, int index) {
        int N = arr.size();
        std::vector<std::string> ans(N - 1);
        int ansIndex = 0;
        for (int i = 0; i < N; i++) {
            if (i != index) {
                ans[ansIndex++] = arr[i];
            }
        }
        return ans;
    }

    // strs中所有字符串全排列,返回所有可能的结果
    static std::set<std::string> process(std::vector<std::string> strs){
        std::set<std::string> ans;
        if(strs.empty()){
            ans.emplace("");
            return ans;
        }

        for (int i = 0; i < strs.size(); ++i) {
            std::string first = strs[i];
            auto nexts = removeIndexString(strs, i);
            auto next = process(nexts);
            for(const auto& cur : next){
                ans.emplace(first + cur);
            }
        }
        return ans;
    }
public:
    std::string lowestString(std::vector<std::string> strs){
        auto ans = process(strs);
        return ans.empty() ? "" : *ans.begin();
    }
};

贪心

(1)错误的贪心策略

可能最直观的解法就是,所有字符串按字典序先排序,将排序后的字符串依次拼接起来就是最后的结果。

反例:[“b”, “ba”],各字符串按字典序先排序的结果是[“b”, “ba”],最后拼接的字符串是"bba",但是本例的最终结果是"bab",因为"bab" < “bba”。所以这样的贪心策略是错的。

(2)正确的贪心策略
对于任意两个字符串 A和B,如果 A与B 的拼接结果小于 B与A 的拼接结果则A排在前面,否则B排在前面,按照这样的策略将整个字符串数组先排序一遍,再将排序后的数组挨个拼接起来得到的结果就是最终的结果。

这时候就存在一个问题了,对于任意的使用贪心策略求解的题,贪心策略的提出是比较容易的,但是如何证明它是正确的就比较难了。

不要忘了,我们有对数器啊,我们可以使用最暴力的解法获取正确答案,再和我们贪心策略获得的结果进行比较,不等则说明我们的贪心策略存在问题,那么,赶紧换另外的贪心策略。

总结:任何贪心策略都是先提出再证明,既然我们有对数器,我们何必再花大力气去用证明的方式来确定贪心策略的正确性呢?证明还是留给做学术研究的人来做吧。

class Solution {

public:
    std::string lowestString(std::vector<std::string> strs){
        if(strs.empty()){
            return "";
        }
        std::sort(strs.begin(), strs.end(), [](std::string &l , std::string & r){
            return (l + r) < (r + l);
        });

        std::string ans ;
        for (auto & str : strs) {
            ans += str;
        }
        return ans;
    }
};

类似题目:179. 最大数

在这里插入图片描述

解答

class Solution {
public:
	string largestNumber(vector<int>& nums) {
		sort(nums.begin(), nums.end(), [](int a, int b) {return to_string(a) + to_string(b) > to_string(b) + to_string(a); });
		string res = accumulate(nums.begin(), nums.end(), string(), [](string &s, int a) {return s + to_string(a); });
		return res[0] == '0' ? "0": res;  // 小心00
	}
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值