剑指OFFER31-40题

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

class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n){
        if(n < 1) return 0;
        if(n < 9) return 1;
        int high = 0;
        int k = 0;
        int cur = 0;
        int count = 0;
        for(int i = 1; k = n / i; i *= 10){
            high = k / 10;
            count += high * i;
            cur = k % 10;
            if(cur > 1)
                count += i;
            else if(cur == 1)
                count += n - k * i + 1;
        }
        return count;   
    }
};

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

class Solution {
public:
    static bool cmp(string x,string y){
        int xl=x.size();
        int yl=y.size();
        int i;
        for(i=0 ; i<xl && i<yl ; i++){
            if(x[i]<y[i])return true;
            if(x[i]>y[i])return false;
        }
        if(i==xl && i<yl){
            return y[i]>=x[0];
        }
        if(i==yl && i<xl){
            return x[i]<=x[0];
        }
        return true;
    }
    string PrintMinNumber(vector<int> numbers) {
        vector<string> s;
        for(int i=0;i<numbers.size();i++){
            stringstream ss;
            ss<<numbers[i];
            string tmp;
            ss>>tmp;
            s.push_back(tmp);
        }
        sort(s.begin(),s.end(),cmp);
        string ans;
        for(int i=0;i<s.size();i++){
            ans+=s[i];
        }
        return ans;
    }
};
/*
1. 字符串到整数
    stringstream sstr(str);
    int x;
    sstr >> x;(即从sstr中提取数据)
2. 整数到字符串
    stringstream sstr;
    int x;
    sstr << x;
    string str = sstr.str();
    */

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

class Solution {
public:
    int GetUglyNumber_Solution(int index) {
        vector<int> ugly(index, -1);
        if (index <= 0) return 0;
        int idx2 = 0, idx3 = 0, idx5 = 0, i = 1;
        ugly[0] = 1;
        while (i<index)
        {
            int new2 = ugly[idx2] * 2;
            int new3 = ugly[idx3] * 3;
            int new5 = ugly[idx5] * 5;
            int tempVal = min(min(new2, new3), new5);
            if (tempVal == new2)
                idx2++;
            if (tempVal == new3)
                idx3++;
            if (tempVal == new5)
                idx5++;
            ugly[i] = tempVal;
            i++;
        }
        return ugly[index - 1];
    }
};

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

class Solution {
public:
    //全部字母则可以用一个26*2的数组存,字符值到下标有映射关系,这里求第一个,排序要带下标就比较烦
    int FirstNotRepeatingChar(string str) {
        int len=str.size();
        int mp[53],id[53];
        memset(mp,0,sizeof(mp));
        memset(id,0,sizeof(id));
        for(int i=0;i<len;i++){
            if(str[i]<='Z')mp[str[i]-'A'+1]++,id[str[i]-'A'+1]=i;
            if(str[i]>='a')mp[str[i]-'a'+27]++,id[str[i]-'a'+27]=i;
        }
        int ans=100;
        for(int i=1;i<53;i++){
            if(mp[i]==1){
                ans=ans<id[i]?ans:id[i];
            }
        }
        if(ans==100)return -1;
        return ans;
    }
};

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

class Solution {
public:
    vector<int> mvDataBack;//临时数组
    long long count = 0;//答案是全局变量
    int InversePairs(vector<int> data) {//传入数据求逆序数
        if(data.empty())return 0;//无数就是0
        mvDataBack.resize(data.size());//设置大小就是DATA的大小
        split(data,0,data.size()-1);//进行分裂
        return count%1000000007;//答案输出
    }
    void split(vector<int> &data,int start,int end){//传入向量,左界,右界
        if(start>=end)return;//只有一个数就跳出了
        split(data,start,(end-start)/2+start);//分裂左半区间
        split(data,(end-start)/2+start+1,end);//分裂右半区间
        merge(data,start,end);//合并整个区间
        for(int i=start;i<=end;i++)data[i] = mvDataBack[i];//把临时数组原封不动赋回原数组
    }
    void merge(vector<int> &data,int start,int end){
        int ind = end;//临时数组整个大扫描指针
        int SplitPos = start+(end-start)/2;//区分位置
        int left = SplitPos,right = end;//扫描指针从右界起
        while(left>=start&&right>SplitPos){//两个指针都未到左界
            if(data[right]>data[left])//右边的数较大,没有构成逆序数
                mvDataBack[ind--] = data[right--]; //用右半区章数赋值
            else{//左边的数较大,就要计COUNT
                mvDataBack[ind--] = data[left--]; //赋值
                count += (right-SplitPos); //统计count,当前右半区间的下标到分裂点的距离就是增加的逆序数对
            }
        }
        while(left>=start)//扫描指针未到左界
            mvDataBack[ind--] = data[left--];//赋值
        while(right>SplitPos)//扫描指针未到右界
            mvDataBack[ind--] = data[right--]; //赋值   //这里无需再进行count的统计
    }

};

36两个链表的第一个公共结点
输入两个链表,找出它们的第一个公共结点。

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        set<ListNode*> st;
        ListNode* p=pHead1;
        while(p!=NULL){
            st.insert(p);
            p=p->next;
        }
        p=pHead2;
        while(p!=NULL){
            if(st.find(p)!=st.end()){
                return p;
            }
            p=p->next;
        }
        return NULL;
    }
};

37数字在排序数组中出现的次数
统计一个数字在排序数组中出现的次数。

class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) {
        int ans=0;
        sort(data.begin(),data.end());
        for(int i=0;i<data.size();i++){
            if(data[i]==k)ans++;
            if(data[i]>k)return ans;
        }
        return ans;
    }
};

38二叉树的深度
输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    
    int dfs(TreeNode* r,int dep){
        if(r==NULL)return dep;
        int d1=dfs(r->left,dep+1);
        int d2=dfs(r->right,dep+1);
        return d1>d2?d1:d2;
    }
    int TreeDepth(TreeNode* pRoot)
    {
        return dfs(pRoot,0);
    }
};

39平衡二叉树
输入一棵二叉树,判断该二叉树是否是平衡二叉树。

class Solution {
public:
    int fl=1;
    //深搜每次返回当前子树的深度,函数中判断到如果有绝对值大于一就清标记位
    int dfs(TreeNode* r,int dep){
        if(r==NULL)return dep;
        int d1=dfs(r->left,dep+1);
        int d2=dfs(r->right,dep+1);
        if( d1-d2<-1 || d1-d2 >1 ) fl=0;
        return d1>d2?d1:d2;
    }
    
    bool IsBalanced_Solution(TreeNode* pRoot) {
        int d=dfs(pRoot,1);
        if(fl==0)return false;
        else return true;
    }
};

40数组中只出现一次的数字
一个整型数组里除了两个数字之外,其他的数字都出现了偶数次。请写程序找出这两个只出现一次的数字。

class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
        sort(data.begin(),data.end());
        int fl=1;
        for(int i=0;i<data.size();i++){
            if(data[i]==data[i+1]){
                i++;
                continue;
            }
            if(fl==1){
                *num1=data[i];
                fl++;
            }
            else if(fl==2){
                *num2=data[i];
                return ;
            }
        }
    }
};

猜你喜欢

转载自blog.csdn.net/cj1064789374/article/details/85010816