数组static_把数组排成最小的数

4bca5d048d08143238001c36107d3770.png

题目描述

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

解题思路及代码

方法一:使用全排列暴力求解

基本思想是对数组中的数进行全排列,然后找出这其中最小的数。

这种方法比较容易想到,但是很明显时间复杂度会很大。

首先我们给出全排列一般化的代码:

void perm(int pos, vector<int> &num, vector<vector<int>> &all_result) {
    if (pos + 1 == num.size()) {
        // 一次全排列的结果
        all_result.push_back(num);
        return;
    }
    for (int i = pos; i < num.size(); ++i) {
        swap(num[pos], num[i]);
        perm(pos+1, num, all_result);
        swap(num[pos], num[i]);
    }
}
int main() {
    vector<int> num = {1, 2, 3};
    vector<vector<int>> all_result;
    perm(0, num, all_result);
}

关于全排列更详细的解释可参考:

LiShun:字符串的排列​zhuanlan.zhihu.com
908ff63880f0eea2ece3b75bcd0424c2.png

然后根据这题的实际情况进行改编,代码如下:

class Solution {
public:
    void perm(int pos, vector<int> &num, string &ret) {
        if (pos + 1 == num.size()) {
            // 一次全排列的结果
            string tmp = "";
            for (int val : num) {
                tmp += to_string(val);
            }
            ret = min(ret, tmp);
            return;
        }
        for (int i = pos; i < num.size(); ++i) {
            swap(num[pos], num[i]);
            perm(pos+1, num, ret);
            swap(num[pos], num[i]);
        }
    }
    string PrintMinNumber(vector<int> nums) {
        string ret(nums.size(), '9'); // nums.size()个'9'
        perm(0, nums, ret);
        return ret;
    }
};
min 函数是可以对字符串进行比较的。

其实我们可以不用自己写全排列的代码,STL中有全排列的库函数 next_permutation(first, last)

用法举例:

#include <iostream>
#include <algorithm>
#include <string>
using namespace std;

int main() {
    string s = "aba";
    sort(s.begin(), s.end());
    do {
        cout<<s<<'n';
    }while(next_permutation(s.begin(), s.end()));

    return 0;
}

/*
output:
aab
aba
baa
*/

那么我们使用库函数的代码是:

class Solution {
public:
    string PrintMinNumber(vector<int> nums) {
        vector<string> str;
        for (int val : nums) {
            str.push_back(to_string(val));
        }   
        sort(str.begin(), str.end());
        string ret(nums.size(), '9');
        do {
            string tmp = "";
            for (string val : str)
                tmp += val;
            ret = min(ret, tmp);
        } while (next_permutation(str.begin(), str.end()));
        return ret;
    }
};

时间复杂度:O(N*N!),全排列的时间复杂度为N!,每次排列结果需要遍历一次nums数组

空间复杂度:O(1)

方法二:自定义排序

可以看成是一个排序问题,在比较两个字符串 S1 和 S2 的大小时,应该比较的是 S1+S2 和 S2+S1 的大小,如果 S1+S2 < S2+S1,那么应该把 S1 排在前面,否则应该把 S2 排在前面。

因为 S1 排在前面可以使结果更小,所以我们可以自定义排序规则,使得 vector 中的字符串都满足这个规则,那么最后得到的结果就是最小的。

算法步骤:

  1. vector<int> 转化为vector<string>
  2. 自定义上述排序规则
  3. 整合结果

对于第二步的排序规则,我们可以通过仿函数lambda表达式函数指针三种方法来实现:

  1. 仿函数
struct Com {
    bool operator() (string a, string b) {
     return a + b < b + a;
    }
};
sort(str.begin(), str.end(), Com()); // Com()为临时对象
仿函数(functor),就是使一个类的使用看上去像一个函数。其实现就是类中实现一个 operator(),这个类就有了类似函数的行为,就是一个仿函数类了。
  1. lambda表达式
// 1. 匿名lambda表达式
sort(str.begin(), str.end(), [](string a, string b) {
     return a + b < b + a;
});
// 2.具名lambda表达式
auto lam = [](string a, string b) {
     return a + b < b + a;
 };
sort(str.begin(), str.end(), lam);;
C++ 11 中的 Lambda 表达式用于定义并创建匿名的函数对象,以简化编程工作。 Lambda 的语法形式如下: [函数对象参数] (操作符重载函数参数) mutable 或 exception 声明 -> 返回值类型 {函数体}
可以看到,Lambda 主要分为五个部分:[函数对象参数]、(操作符重载函数参数)、mutable 或 exception 声明、-> 返回值类型、{函数体}.
  1. 函数指针
bool static com(string a, string b) {
    return a + b < b + a;
}
//加static的原因:类成员函数有隐藏的this指针,static 可以去this指针
sort(str.begin(), str.end(), com);

最后的代码为:

class Solution {
public:
    string PrintMinNumber(vector<int> nums) {
        vector<string> str;
        for (int val : nums) str.push_back(to_string(val));
        sort(str.begin(), str.end(), [](string a, string b) {
            return a + b < b + a;
        });
        string ret = "";
        for (string s : str) ret += s;
        return ret;
    }
};

Java 版:

public String PrintMinNumber(int[] numbers) {
    if (numbers == null || numbers.length == 0)
        return "";
    int n = numbers.length;
    String[] nums = new String[n];
    for (int i = 0; i < n; i++)
        nums[i] = numbers[i] + "";
    Arrays.sort(nums, (s1, s2) -> (s1 + s2).compareTo(s2 + s1));
    String ret = "";
    for (String str : nums)
        ret += str;
    return ret;
}

时间复杂度:O(NlogN), 采用了排序

空间复杂度:O(N)


部分参考来自:

把数组排成最小的数_牛客网​www.nowcoder.com
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值