剑指offer刷题记录(C++)

本文精选了66道经典算法题目,涵盖了从二维数组查找、字符串处理、链表操作到复杂数据结构如二叉树、图的遍历,以及数学、概率、动态规划等多个领域的算法问题。每道题目都附带了详细的解决方案,旨在帮助读者深入理解算法原理,提高编程技能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.二维数组的查找

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        int m=array.size();
        if(m==0)return false;
        int n=array[0].size();
        int row=0,col=n-1;
        while(row<m && col>=0){
            if(array[row][col]==target)return true;
            else if(array[row][col]>target)col--;
            else row++;
        }
        return false;
        
    }
};

2.替换空格

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

class Solution {
public:
    void replaceSpace(char *str,int length) {//length 为数组总容量
        int strsize=0;
        int space=0;
        for(int i=0;i<length;i++){
            if(str[i]=='\0')break;
            ++strsize;
            if(str[i]==' ')++space;
        }
        if(strsize+2*space>length)return;
        char *left=str+strsize,*right=left+2*space;
        *right='\0';
        while(left<right){
            if(*left==' '){
                *(right--)='0';
                *(right--)='2';
                *(right--)='%';
                left--;
            }else{
                *(right--)=*(left--);
            }
        }

    }
};

3.从头到尾打印链表

输入一个链表,按链表从尾到头的顺序返回一个ArrayList。

/**
*  struct ListNode {
*        int val;
*        struct ListNode *next;
*        ListNode(int x) :
*              val(x), next(NULL) {
*        }
*  };
*/
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        if(head==NULL)return {};
        vector<int> res=printListFromTailToHead(head->next);
        res.push_back(head->val);
        return res;
    }
};

4.重建二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        if(pre.size()==0)return NULL;
        TreeNode* res=func(pre,vin,0,pre.size()-1,0,vin.size()-1);
        return res;
    }
    
    TreeNode* func(vector<int> &pre,vector<int> &in,int preleft, int preright,int inleft,int inright){
        if(preleft>preright || inleft>inright)return NULL;
        int val=pre[preleft],inroot;
        for(int i=inleft;i<=inright;i++){
            if (in[i]==val){
                inroot=i;
                break;
            }
        }
        TreeNode* root=new TreeNode(val);
        root->left=func(pre,in,preleft+1,inroot-inleft+preleft,inleft,inroot-1);
        root->right=func(pre,in,inroot-inleft+preleft+1,preright,inroot+1,inright);
        return root;
    }
};

5.用两个栈实现队列

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

class Solution
{
public:
    void push(int node) {
        stack1.push(node);
    }

    int pop() {
        if(stack2.empty()){
            while(!stack1.empty()){
                stack2.push(stack1.top());
                stack1.pop();
            }
        }
        int res=stack2.top();
        stack2.pop();
        return res;
    }

private:
    stack<int> stack1;
    stack<int> stack2;
};

6.旋转数组的最小数字

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

class Solution {
public:
    int minNumberInRotateArray(vector<int> rotateArray) {
        if(rotateArray.size()==0)return 0;
        int l=0,r=rotateArray.size()-1,mid;
        while(l<r){
            mid=(l+r)/2;
            if(rotateArray[l]>=rotateArray[r]){
                if(rotateArray[mid]>=rotateArray[l]){
                    l=mid+1;
                }
                else{
                    r=mid;
                }
            }
            else{
                break;
            }
        }
        return rotateArray[l]; 
    }
};

7.斐波那契数列

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。

n<=39

class Solution {
private:
    vector<int> res;
public:
    Solution(){
        res.resize(40);
       res[0]=0;
        res[1]=1;
        for(int i=2;i<40;i++)res[i]=res[i-1]+res[i-2];
    }
    int Fibonacci(int n) {
        return res[n];

    }
};

8.跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

class Solution {
public:
    int jumpFloor(int number) {
        if(number<=2)return number;
        int prepre=1,pre=2,cur;
        for(int i=3;i<=number;i++){
            cur=pre+prepre;
            prepre=pre;
            pre=cur;
        }
        return cur;
    }
};

9.变态跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

class Solution {
public:
    int jumpFloorII(int number) {
        return pow(2,number-1);
    }
};

10.矩形覆盖

我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

class Solution {
public:
    int rectCover(int number) {
        if(number<2)return number;
        vector<int> dp(number+1);
        dp[0]=dp[1]=1;
        for(int i=2;i<=number;i++)
            dp[i]=dp[i-1]+dp[i-2];
            //最后一块板子横着放或者竖着放,分别对应i-1和i-2
        return dp[number];

    }
};

11.二进制中1的个数

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

class Solution {
public:
     int  NumberOf1(int n) {
         int count=0;
         while(n){
             n=n&(n-1);
             count++;
         }
         return count;
     }
};

12.数值的整数次方

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

保证base和exponent不同时为0

class Solution {
public:
    double Power(double base, int exponent) {
        if(exponent==0)return 1.0;
        if(base==0)return 0.0;
        if(exponent==1) return base;
        if(exponent<0) return 1.0/Power(base,-exponent);
        double res=1.0,temp=base;
        for(int i=1;i<exponent;i*=2){
            if(exponent&i)res*=temp;
            temp*=temp;
        }
        return res;
    }
};

13.调整数组顺序使奇数位于偶数前面

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

class Solution {
public:
    void reOrderArray(vector<int> &array) {
        for(int i=1;i<array.size();i++){
            for(int j=i;j>0;j--){
                if(array[j]%2!=0&&array[j-1]%2==0)
                    swap(array[j],array[j-1]);
            }
        }
    }
};

14.链表中倒数第k个结点

输入一个链表,输出该链表中倒数第k个结点。

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(pListHead==NULL||k<1)return NULL;
        ListNode* left=pListHead,*right=pListHead;
        for(int i=1;i<k;i++){
            right=right->next;
            if(right==NULL)return NULL;
        }
        while(right->next){
            right=right->next;
            left=left->next;
        }
        return left;
    }
};

15.反转链表

输入一个链表,反转链表后,输出新链表的表头。

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        ListNode *cur=pHead,*next,*pre=NULL;
        while(cur!=NULL){
            next=cur->next;
            cur->next=pre;
            pre=cur;
            cur=next;
        }
        return pre;

    }
};

16.合并两个排序的链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

/*
struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
	}
};*/
class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        if(pHead1==NULL&&pHead2==NULL)return NULL;
        if(pHead1==NULL||pHead2==NULL)return pHead1?pHead1:pHead2;
        if(pHead1->val<pHead2->val){
            pHead1->next=Merge(pHead1->next,pHead2);
            return pHead1;
        }
        else{
            pHead2->next=Merge(pHead1,pHead2->next);
            return pHead2;
        }
    }
};

17.树的子结构

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
    {
        if(pRoot1==NULL&&pRoot2==NULL)return false;
        if(pRoot1==NULL||pRoot2==NULL)return false;//空树不是子结构
        if (isSub(pRoot1,pRoot2))return true;
        return HasSubtree(pRoot1->left,pRoot2)||HasSubtree(pRoot1->right,pRoot2);
    }
    bool isSub(TreeNode* root1,TreeNode* root2){
        if(root2==NULL)return true;
        if(root1==NULL)return false;
        if(root1->val!=root2->val)return false;
        return isSub(root1->left,root2->left)&&isSub(root1->right,root2->right);
    }
};

对比:判断二叉树的子树

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isSubtree(TreeNode* s, TreeNode* t) {
        if(s==NULL && t==NULL)return true;
        if(s==NULL || t==NULL)return false;
        if(isSame(s,t))return true;
        return isSubtree(s->left,t)||isSubtree(s->right,t);
    }
private:
    bool isSame(TreeNode* s, TreeNode* t){
        if(s==NULL && t==NULL)return true;
        if(s==NULL || t==NULL)return false;
        if(s->val!=t->val)return false;
        return isSame(s->left,t->left)&&isSame(s->right,t->right);
    }
};

18.二叉树的镜像

操作给定的二叉树,将其变换为源二叉树的镜像。

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    void Mirror(TreeNode *pRoot) {
        helper(pRoot);
    }
    
    TreeNode* helper(TreeNode *root){
        if(root==NULL){
            return NULL;
        }
        TreeNode* temp=root->left;
        root->left=helper(root->right);
        root->right=helper(temp);
        return root;
    }
};

19.顺时针打印矩阵

输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

class Solution {
public:
    vector<int> printMatrix(vector<vector<int> > matrix) {
        vector<int> res;
        if(matrix.size()==0||matrix[0].size()==0)return res;
        int m=matrix.size();
        int n=matrix[0].size();
        for(int level=0;2*level<m && 2*level<n;level++){
            for(int i=level;i<n-level;i++)res.push_back(matrix[level][i]);
            for(int j=level+1;j<m-level-1;j++)res.push_back(matrix[j][n-level-1]);
            if(m-level-1>level)for(int i=n-level-1;i>=level;i--)res.push_back(matrix[m-level-1][i]);
            if(n-level-1>level)for(int j=m-level-2;j>level;j--)res.push_back(matrix[j][level]);
        }
        return res;

    }
};

20.包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

class Solution {
public:
    void push(int value) {
        s.push(value);
        if(sm.empty()||sm.top()>=value)sm.push(value);
    }
    void pop() {
        if(sm.top()==s.top())sm.pop();
        s.pop();
    }
    int top() {
        return s.top();
    }
    int min() {
        return sm.top();
    }
    stack<int> s,sm;
};

21.栈的压入、弹出序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

class Solution {
public:
    bool IsPopOrder(vector<int> pushV,vector<int> popV) {
        stack<int> st;
        int pushInd=0,popInd=0;
        while(pushInd<pushV.size()){
            st.push(pushV[pushInd++]);
            while(!st.empty() && st.top()==popV[popInd]){
                st.pop();
                popInd++;
            }
        }
        return popInd==popV.size();
    }
};

22.从上往下打印二叉树

从上往下打印出二叉树的每个节点,同层节点从左至右打印。

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {
        vector<int> res;
        if(root==NULL)return res;//attention!
        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty()){
            TreeNode *front=q.front();
            res.push_back(front->val);
            q.pop();
            if(front->left)q.push(front->left);
            if(front->right)q.push(front->right);
            
        }
        return res;

    }
};

23.二叉搜索树的后序遍历序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

class Solution {
public:
    bool VerifySquenceOfBST(vector<int> sequence) {
        if(sequence.size()==0)return false;
        return func(sequence,0,sequence.size()-1);
    }
    bool func(vector<int> &post,int left,int right){
        if(left>=right)return true;
        int indexl=left-1,indexr=right;
        while(post[indexl+1]<post[right])indexl++;
        while(post[indexr-1]>post[right])indexr--;
        bool res=(indexl+1==indexr);
        return res&&func(post,left,indexl)&&func(post,indexr,right-1);
    }
};

24.二叉树中和为某一值的路径

输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
        vector<vector<int>> res;
        vector<int> temp;
        if(root==NULL)return res;
        dfs(root,expectNumber,res,temp);
        sort(res.begin(),res.end(),cmp);
        return res;
    }
    bool static cmp(vector<int>a,vector<int> b){
        return a.size()>b.size();
    }
    void dfs(TreeNode* root,int num, vector<vector<int>> &res, vector<int> &temp){
        //题目没有说所有节点为正整数
        if(root->left==NULL && root->right==NULL){
            if(num==root->val){
                temp.push_back(root->val);
                res.push_back(temp);
                temp.pop_back();
            }
            return;
        }
        temp.push_back(root->val);
        if(root->left)dfs(root->left,num-root->val,res,temp);
        if(root->right)dfs(root->right,num-root->val,res,temp);
        temp.pop_back();
    }
};

25.复杂链表的复制

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

/*
struct RandomListNode {
    int label;
    struct RandomListNode *next, *random;
    RandomListNode(int x) :
            label(x), next(NULL), random(NULL) {
    }
};
*/
class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead)
    {
        if(pHead==NULL)return NULL;
        RandomListNode* cur=pHead,*next;
        while(cur!=NULL){
            next=cur->next;
            cur->next=new RandomListNode(cur->label);
            cur->next->next=next;
            cur->next->random=cur->random;
            cur=next;
        }
        cur=pHead->next;
        while(cur->next!=NULL){ //attention next
            cur->random=cur->random?cur->random->next:NULL;//attention ?:
            cur=cur->next->next;
        }
        RandomListNode* res=pHead->next;
        cur=pHead;
        while(cur!=NULL){
            next=cur->next->next;
            cur->next->next=next?next->next:NULL;
            cur->next=next;
            cur=next;
        }
        return res;
    }
};

26.二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

/*
struct TreeNode {
	int val;
	struct TreeNode *left;
	struct TreeNode *right;
	TreeNode(int x) :
			val(x), left(NULL), right(NULL) {
	}
};*/
class Solution {
public:
    TreeNode* Convert(TreeNode* pRootOfTree)
    {
        if(pRootOfTree==NULL)return NULL;
        TreeNode* pre=NULL;
        inorder(pRootOfTree,pre);
        TreeNode* res=pRootOfTree;
        while(res->left)res=res->left;//注意是while
        return res;
    }
    
    void inorder(TreeNode* cur, TreeNode* &pre)
    {
        if(cur==NULL) return;
        inorder(cur->left,pre);
        if(pre)pre->right=cur;
        cur->left=pre;
        pre=cur;
        inorder(cur->right,pre);
    }
};

27.字符串的排列

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

class Solution {
public:
    vector<string> Permutation(string str) { //需要排除重复字符串,字典序排列
        vector<string> res;
        set<string> s;
        if(str=="")return res;
        dfs(str,0,res,s);
        sort(res.begin(),res.end());//字典序排列,只需sort一下emmm
        return res;
    }
    void dfs(string &str,int begin,vector<string> &res,set<string> &s){
        if(begin==str.size()){
            if(s.find(str)==s.end()){
                res.push_back(str);
            }
            s.insert(str);
        }
        else{
            for(int i=begin;i<str.size();i++){
                swap(str[i],str[begin]);
                dfs(str,begin+1,res,s);
                swap(str[i],str[begin]);
            }
        }
    }
};

图源:牛客网用户HAHA7877

28.数组中出现次数超过一次的数字

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

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        int res=numbers[0],cur=1;
        for(int i=1;i<numbers.size();++i){
            if(cur==0){
                res=numbers[i];
                cur=1;
            }
            if(numbers[i]==res)++cur;
            else --cur;
        }
        //题目还有可能不存在
        int num=count(numbers.begin(),numbers.end(),res);
        if(num*2>numbers.size())return res;
        else return 0;
    }
};

29.最小的K个数

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

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> res;
        if(k<1||input.size()<k)return res;//attention
        else{
            int st=0,ed=input.size()-1;
            int index=partition(input,st,ed);
            while(index!=k-1){
                if(index>k-1){
                    ed=index-1;
                    index=partition(input,st,ed);
                }
                else {
                    st=index+1;
                    index=partition(input,st,ed);
                }
            }
            for(int i=0;i<k;i++)res.push_back(input[i]);
        }
        sort(res.begin(),res.end());
        return res;
    }
    
    int partition(vector<int> &input,int st,int ed){
        int pivot=input[st];
        int l=st,r=ed;
        while(l!=r){
            while(l<r&&input[r]>pivot)r--;
            while(l<r&&input[l]<=pivot)l++;
            if(l<r)swap(input[l],input[r]);
        }
        swap(input[st],input[l]);
        return l;
    }
};

30.连续子数组的最大和

HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)

class Solution {
public:
    int FindGreatestSumOfSubArray(vector<int> array) {
        int res=array[0],temp=0;
        for(int i=0;i<array.size();i++){
            temp+=array[i];
            if(temp>res)res=temp;
            if(temp<0)temp=0;
        }
        return res;
    }
};

31.整数中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)
    {
        int res=0,cur=1,right,left,num;
        while(n/cur){
            left=n/cur/10;
            right=n%cur;
            num=n/cur%10;
            if(num==0)res+=left*cur;
            else if(num==1)res+=left*cur+right+1;
            else res+=(left+1)*cur;
            cur*=10;
        }
        return res;
    }
};

32.把数组排成最小的数

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

class Solution {
public:
    string PrintMinNumber(vector<int> numbers) {
        sort(numbers.begin(),numbers.end(),cmp);
        string res;
        for(auto it:numbers)res+=to_string(it);
        return res;
        
    }
    
    bool static cmp(int a,int b){
        return to_string(a)+to_string(b)<to_string(b)+to_string(a);
    }
};

33.丑数

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

class Solution {
public:
    int GetUglyNumber_Solution(int index) {
        if(index<1)return 0;
        vector<int> res(index); //空间换时间
        res[0]=1;
        int cur2=0,cur3=0,cur5=0;
        for(int i=1;i<index;i++){
            res[i]=min(res[cur2]*2,min(res[cur3]*3,res[cur5]*5));
            if(res[i]==res[cur2]*2)cur2++;
            if(res[i]==res[cur3]*3)cur3++;
            if(res[i]==res[cur5]*5)cur5++;
        }
        return res[index-1];
    }
};

 

34.第一个只出现一次的字符

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

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

35.数组中的逆序对

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

class Solution {
public:
    int mod=1000000007;
    int InversePairs(vector<int> data) {
        if(data.size()<=1)return 0;
        vector<int> copy(data);
        int res=fun(data,copy,0,data.size()-1);
        return res;
    }
    int fun(vector<int> &data,vector<int> &copy, int start, int end ){
        if(start==end)
        {
            copy[start]=data[start];
            return 0;
        }
        int length=(end-start)/2;
        int left=fun(copy,data,start,start+length);
        int right=fun(copy,data,start+length+1,end);
        
        int i=start+length;
        int j=end;
        int indexcopy=end;
        int count=0;
        while(i>=start && j>=start+length+1){
            if(data[i]>data[j]){
                copy[indexcopy--]=data[i--];
                count=(count+j-(start+length))%mod;
            }
            else copy[indexcopy--]=data[j--];
        }