刷题笔记-2020.06.06

1. 把数组排成最小的数

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。
  分析:之前做过这道题,这次做的第一个想法和之前一样,首先要将数字转成字符串,然后比较字符串的大小,而且比较的结果应该是“321”<“32” && "32"<"3",或许我们可以这样考虑“32”==“322” && "3"=="33"。所以需要这样判断,当比较 “321” 与 “32” 时,他们的前两个字符相等,而 “321” 的第三个字符小于 “32” 的第二个字符,于是我们得出 “321”<“32” 的结论。想法看起来十分复杂又难实现。
  今天在纸上写下“32132<32321”的时候,突然脑袋开窍。我们可以通过判断 str1+str2str2+str1 的关系得到两字符串的大小啊!于是编程如下:

class Solution {
public:
    
    static bool strcmp(const string& str1, const string& str2)
    {//这里一定要是静态函数,因为静态函数指针等同于函数指针,
    //而非静态函数指针比普通函数指针多了一个类名。
        if(str1+str2<str2+str1) //str1<str2,升序排序
            return true;
        else return false;
    }
    
    string PrintMinNumber(vector<int> numbers) {
        vector<string> vecstr;
        int size = numbers.size(), i;
        for(i=0; i<size; ++i)
            vecstr.push_back(to_string(numbers[i]));
        sort(vecstr.begin(),vecstr.end(),strcmp);
        string ret;
        for(i=0; i<size; ++i)
            ret += vecstr[i];
        return ret;
    }
};

2. 丑数.

把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。
  分析:最小的丑数是 1,并且除了 1 之外的所有丑数都是由其他丑数 *2 或 *3 或 *5 得到的。设置一个丑数序列 ugly,每次找到一个稍大的丑数就放进队列,再设置三个指针 pos2、pos3、pos5,分别指向 2、3、5 三个数想要乘的丑数。下一个添加进队列的丑数是 ugly[pos2]*2、ugly[pos3]*3、ugly[pos3]*3 的最小值。如果新得到的丑数是由 2 乘之前某个丑数得到的,就把 pos2 指针移向下一位。

class Solution {
public:
    int GetUglyNumber_Solution(int index) {
        if(index<=0) return 0;
        vector<int> ugly(index);
        ugly[0]=1;
        int pos2=0, pos3=0, pos5=0;
        for(int i=1; i<index; ++i)
        {
            ugly[i] = min(min(ugly[pos2]*2, ugly[pos3]*3), ugly[pos5]*5);
            if(ugly[pos2]*2 == ugly[i]) ++pos2;
            if(ugly[pos3]*3 == ugly[i]) ++pos3;
            if(ugly[pos5]*5 == ugly[i]) ++pos5;
        }
        return ugly[index-1];
    }
};

3. 第一个只出现1次的字符

在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)
  分析:奇怪的事情发生了——在牛客的编辑器上提示 unordered_map 是未声明的 identifier,但是仍然能通过百分百的用例。
  ps:本以为这道题有什么神奇的解法呢。

class Solution {
public:
    int FirstNotRepeatingChar(string str) {
        unordered_map<char, int> cnt;
        for(int i=0; i<str.length(); ++i)
            ++cnt[str[i]];
        for(int i=0; i<str.length(); ++i)
            if(cnt[str[i]]==1)
                return i;
        return -1;
    }
};

4. 数组中的逆序对.

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数 P 。并将 P 对 1000000007 取模的结果输出。 即输出P % 1000000007。题目保证输入的数组中没有的相同的数字,数据范围:
对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5
分析:归并排序的应用

class Solution {
public:
    int mod = 1000000007;
    
    void merge(vector<int>& data, vector<int>& tmp, int l, int mid, int r, int &ret)
    {
        int t=0, i=l, j=mid+1;
        while(i<=mid && j<=r)
        {
            if(data[i]>data[j])
            {
                tmp[t++] = data[j++];
                ret += (mid-i+1);
                ret %= mod;
            }else{
                tmp[t++] = data[i++];
            }
        }
        while(i<=mid)
            tmp[t++] = data[i++];
        while(j<=r)
            tmp[t++] = data[j++];
        for(i=0; i<=r-l; ++i)
            data[l+i] = tmp[i];
    }
    
    void split_merge(vector<int>& data, vector<int>& tmp, int l, int r, int& ret)
    {
        if(l>=r) return;
        int mid = l+((r-l)>>1);
        split_merge(data, tmp, l, mid, ret);
        split_merge(data, tmp, mid+1, r, ret);
        merge(data, tmp, l, mid, r, ret);
    }
    
    int InversePairs(vector<int> data) {
        int size = data.size(), ret=0;
        vector<int> tmp(size);
        split_merge(data, tmp, 0, size-1, ret);
        return ret;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值