数组中出现次数超过一半的数字

题目描述

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

思路

数组排序后,如果符合条件的数存在,则一定是数组中间那个数。
(比如:1,2,2,2,3;或2,2,2,3,4;或2,3,4,4,4等等)
这种方法虽然容易理解,但由于涉及到快排sort,其时间复杂度为O(NlogN)并非最优;

代码

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        if(numbers.size()==0)
            return 0;
        sort(numbers.begin(),numbers.end());
        int middle = numbers[numbers.size()/2];
        int count = 0;
        for(int i=0;i<numbers.size();i++){
            if(numbers[i]==middle)
                count++;
        }
        if(count>numbers.size()/2)
            return middle;
        else
            return 0;
    }
};

最小的k个数

题目描述

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

思路

全排序 时间复杂度O(nlogn)

代码

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> res;
        if(input.empty()||k==0||k>input.size())
            return res;
        sort(input.begin(),input.end());
        for(int i=0;i<k;i++){
            res.push_back(input[i]);
        }
        return res;
    }
};

整数中1出现的次数(从1到n整数中出现1的个数)

题目描述

求出113的整数中1出现的次数,并算出1001300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

思路

可以直接暴力搜索0~n每个数字中有几个1,之后累加就行

代码

class Solution {
public:
    int count1(int n){
        int count = 0;
        while(n){
            if(n%10==1)
                ++count;
            n = n/10;
        }
        return count;
    }
    int NumberOf1Between1AndN_Solution(int n)
    {
        int count = 0;
        for(int i=1;i<=n;i++){
            count += count1(i);
        }
        return count;
    }
};

把数组排成最小的数

题目描述

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

思路

对vector容器内的数据进行排序,按照 将a和b转为string后
若 a+b<b+a a排在在前 的规则排序,
如 2 21 因为 212 < 221 所以 排序后为 21 2
to_string() 可以将int 转化为string

sort中的比较函数compare要声明为静态成员函数或全局函数,不能作为普通成员函数,否则会报错。
因为:非静态成员函数是依赖于具体对象的,而std::sort这类函数是全局的,因此无法再sort中调
用非静态成员函数。静态成员函数或者全局函数是不依赖于具体对象的, 可以独立访问,无须创建任何
对象实例就可以访问。同时静态成员函数不可以调用类的非静态成员。

代码

class Solution {
public:
    static bool cmp(int a,int b){//必须加static
        string A = "";
        string B = "";
        A += to_string(a);
        A += to_string(b);
        B += to_string(b);
        B += to_string(a);
        return A < B;
    }
    string PrintMinNumber(vector<int> numbers) {
        string answer = "";
        sort(numbers.begin(), numbers.end(),cmp);
        for(int i=0;i<numbers.size();i++)
            answer += to_string(numbers[i]);
        return answer;
    }
};

丑数

题目描述

把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

思路

首先从丑数的定义我们知道,一个丑数的因子只有2,3,5,那么丑数p = 2 ^ x * 3 ^ y * 5 ^ z,换句话说一个丑数一定由另一个丑数乘以2或者乘以3或者乘以5得到,那么我们从1开始乘以2,3,5,就得到2,3,5三个丑数,在从这三个丑数出发乘以2,3,5就得到4,6,10,6,9,15,10,15,25九个丑数,我们发现这种方法得到重复的丑数,而且我们题目要求第N个丑数,这样的方法得到的丑数也是无序的。

代码

class Solution {
public:
    int GetUglyNumber_Solution(int index) {
        if(index<7)
            return index;
        int p2 = 0, p3 = 0, p5 = 0;
        int newNum = 1;
        vector<int> arr;
        arr.push_back(newNum);
        while(arr.size() < index){
            newNum = min(arr[p2]*2,min(arr[p3]*3,arr[p5]*5));
            if(arr[p2]*2==newNum) p2++;
            if(arr[p3]*3==newNum) p3++;
            if(arr[p5]*5==newNum) p5++;
            arr.push_back(newNum);
        }
        return newNum;
    }
};

第一个只出现一次的字符

题目描述

在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写)。

思路

用一个map来记录每个元素出现的次数,然后再遍历一遍,第一个出现次数为一的数返回。

代码

class Solution {
public:
    int FirstNotRepeatingChar(string str) {
        map<char, int> mp;
        for(int i=0; i<str.size();i++){
            mp[str[i]]++;
        }
        for(int i=0; i<str.size();i++){
            if(mp[str[i]]==1)
                return i;//注意是返回位置
        }
        return -1;
    }
};

数组中的逆序对

题目描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

输入描述:

题目保证输入的数组中没有的相同的数字数据范围:
对于%50的数据,size<=10^4    
对于%75的数据,size<=10^5    
对于%100的数据,size<=2*10^5

思路

一般方法:直接暴力穷举,O(n^2),超时
优化方法:类归并排序方法,O(nlog(n))

代码

class Solution {
public:
    int InversePairs(vector<int> data) {
        if(data.size()<=1) return 0;//如果少于等于1个元素,直接返回0
        int* copy=new int[data.size()];
        //初始化该数组,该数组作为存放临时排序的结果,最后要将排序的结果复制到原数组中
        for(unsigned int i=0;i<data.size();i++)
            copy[i]=0;
        //调用递归函数求解结果
        int count=InversePairCore(data,copy,0,data.size()-1);
        delete[] copy;//删除临时数组
        return count;
    }
     //程序的主体函数
    int InversePairCore(vector<int>& data,int*& copy,int start,int end)
    {
        if(start==end)
        {
            copy[start]=data[start];
            return 0;
        }
        //将数组拆分成两部分
        int length=(end-start)/2;//这里使用的下标法,下面要用来计算逆序个数;也可以直接使用mid=(start+end)/2
        //分别计算左边部分和右边部分
        int left=InversePairCore(data,copy,start,start+length)%1000000007;
        int right=InversePairCore(data,copy,start+length+1,end)%1000000007;
        //进行逆序计算
        int i=start+length;//前一个数组的最后一个下标
        int j=end;//后一个数组的下标
        int index=end;//辅助数组下标,从最后一个算起
        int count=0;
        while(i>=start && j>=start+length+1)
        {
            if(data[i]>data[j])
            {
                copy[index--]=data[i--];
                //统计长度
                count+=j-start-length;
                if(count>=1000000007)//数值过大求余
                    count%=1000000007;
            }
            else
            {
                copy[index--]=data[j--];
            }
        }
        for(;i>=start;--i)
        {
            copy[index--]=data[i];
        }
        for(;j>=start+length+1;--j)
        {
            copy[index--]=data[j];
        }
        //排序
        for(int i=start; i<=end; i++) {
            data[i] = copy[i];
        }
        //返回最终的结果
        return (count+left+right)%1000000007;
    }
};

两个链表的第一个公共节点

题目描述

输入两个链表,找出它们的第一个公共结点。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

思路

两个链表相交,肯定是一个Y型,所以只要找到长度差,之后长的先走,走到两者剩下的长度相同时,开始同时走,直到遇到第一个公共节点。

代码

class Solution {
public:
    int calculateLen(ListNode* root){
        int count = 0;
        while(root){
            count++;
            root=root->next;
        }
        return count;
    }

    ListNode* walkNStep(ListNode* root, int steps){
        for(int i=0;i<steps;i++){
            root = root->next;
        }
        return root;
    }

    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        int len1 = calculateLen(pHead1);
        int len2 = calculateLen(pHead2);
        if(len1>len2){
            pHead1 = walkNStep(pHead1, len1-len2);
        }else{
            pHead2 = walkNStep(pHead2, len2-len1);
        }
        while(pHead1){
            if(pHead1==pHead2)
                return pHead1;
            pHead1 = pHead1->next;
            pHead2 = pHead2->next;
        }
        return NULL;
    }
};


实习      C++ 牛课网

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!