剑指offer

目录


1.二维数组中的查找

题目链接

题目描述:

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

解题思路:

该二维数组中的一个数,小于它的数一定在其左边,大于它的数一定在其下边

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

2.替换空格

题目链接

题目描述:

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

解题思路:

先获取替换后的长度 然后倒着往前添加即可

class Solution {
public:
    void replaceSpace(char *str,int length) {
     int len = 0;
     for(int j=0;j<length;j++){
        if(str[j]==' ') len+=3;
        else len++;
     }
     char *s = str+len; s--;
     for(int j=length-1;j>=0;j--){
        if(str[j]==' '){
           *s--='0';
           *s--='2';
           *s--='%';
        }else *s--=str[j];
     }
    }
};

3.从头到尾打印链表

题目链接

题目描述:

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

解题思路:

遍历链表用栈存起来,然后清空栈即可

class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        std::vector<int>q;
        std::stack<int>st;
        ListNode *p = head;
        while(p!=NULL){
            st.push(p->val);
            p = p->next;
        }
        while(!st.empty()){
            q.push_back(st.top());
            st.pop();
        }
        return q;
    }
};

4.重建二叉树

题目链接

题目描述:

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

解题思路:

根据二叉树先序(中左右)和中序(左中右)遍历的性质,我们知道每一个节点的左边都是他的左子树右边是他的右子树,根据这个性质我们每次递归拆分树即可

class Solution {
public:
     TreeNode* work(vector<int> pre,int l,int r,vector<int> vin,int x,int y){
        if(l>=r||x>=y) return NULL;
        int i ;
        for(i = x;i<y;i++){
           if(pre[l]==vin[i]) break;
        }
        TreeNode* node = new TreeNode(pre[l]);
        node->left = work(pre,l+1,l+i-x+1,vin,x,i);
        node->right = work(pre,l+i-x+1,r,vin,i+1,y);
        return node;
    }
  
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        int l = 0,r = pre.size();
        int x = l,y = r;
        return work(pre,l,r,vin,x,y);
    }
};

5.用两个栈实现队列

题目链接

题目描述:

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

解题思路:

简单题

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

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

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;
       else{int l = 0, r = rotateArray.size()-1;
           while(l<r){
               int mid = (l+r)/2;
               if(rotateArray[l]<rotateArray[r]) return rotateArray[l]; // 当最左边的值小于最右边的时候说明 L ~ R 之间一定是单调的
               else if(rotateArray[l]<rotateArray[mid]) l = mid+1;      // L ~ mid 之间是单调时 最小的数一定在 mid+1 ~ R之间
               else if(rotateArray[r]>rotateArray[mid]) r = mid;        // mid ~ R 之间单调的时候 最小的数一定在 L ~ mid 之间
               else l++;                                                // 当相等的时候 我们一定要一点一点往前推进防止 {2,1,2,,2,2}这种情况
           }
           return rotateArray[l];
       }
    }
};

7.斐波那契数列

题目链接

题目描述:

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

解题思路

简单题

class Solution {
public:
    int a[100]={0,1,1};
    void work(){
        for(int j=3;j<=40;j++){
            a[j] = a[j-1]+a[j-2];
        }
    }
    int Fibonacci(int n) {
        work();
        return a[n]; 
    }
};

8.跳台阶

题目链接

题目描述:

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

解题思路

简单题

class Solution {
public:
    int dp[1000]={0,1,2};
    void work(){
        for(int j=3;j<=100;j++){
            dp[j] = dp[j-1]+dp[j-2];
        }
    }
    int jumpFloor(int n) {
        work();
        return dp[n]; 
    }
};

9.变态跳台阶

题目链接

题目描述:

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

解题思路

简单题

class Solution {
public:
    int jumpFloorII(int number) {
        return (1<<(number-1));
    }
};

10.矩形覆盖

题目链接

题目描述:

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

解题思路

点击这里

class Solution {
public:
    int a[100]={0,1,2,3};
    void work(){
        for(int j=4;j<=50;j++){
            a[j] = a[j-1]+a[j-2];
        }
    }
    int rectCover(int number) {
        work();
        return a[number];
    }
};

11.二进制中1的个数

题目链接

题目描述:

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

解题思路

我们知道负数的补码 等于全部取反在 +1 然后利用位运算求一下就 ok

class Solution {
public:
     int  NumberOf1(int n) {
         if(n<0){
             n = abs(n);
             n = ~n;
             n+=1;
         }
         int ans = 0;
         for(int j=0;j<32;j++){
             if((n&(1<<j))){
                 ans++;
             }
         }
         return ans ;
     }           
};

12.数值的整数次方

题目链接

题目描述:

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

解题思路

原来还有负数 先用快速幂求出结果 负数的话就用 1/ans 就好了

class Solution {
public:
    double poww(double a,int b){
        double ans = 1;
        while(b){
            if(b%2){
                ans = ans*a;
            }
            b/=2;
            a*=a;
        }
        return ans ;
    }
    double Power(double base, int exponent) {
        double k = poww(base,abs(exponent));
        if(exponent>0) return k;
        return 1/k;
    }
};

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

题目链接

题目描述:

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

解题思路

空间换时间 遍历两次即可

class Solution {
public:
    void reOrderArray(vector<int> &array) {
        vector<int>q;
        for(int j=0;j<array.size();j++){
            if(array[j]%2){
                q.push_back(array[j]);
            }
        }
        
        for(int j=0;j<array.size();j++){
            if(array[j]%2==0){
                q.push_back(array[j]);
            }
        }
        array = q;
        
    }
};

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

题目链接

题目描述:

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

解题思路

链表模拟

class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        ListNode* p = pListHead;   
        int i = 0;
        while(p!=NULL){
            p = p->next;
            i++;
        }
        if(k>i) return NULL;
        ListNode* pp = pListHead;
        int ii = 0,iii = i-k;
        while(ii<iii){
            pp = pp->next;
            ii++;
        }
        //pp->next = NULL;
        return pp;
    }
};

15.反转链表

题目链接

题目描述:

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

解题思路

链表模拟

class Solution {
public:
    ListNode* ReverseList(ListNode* pHead) {
        ListNode* p = pHead;
        ListNode* pp = NULL;
        while(p!=NULL){
            ListNode* ppp = p->next;
            p->next = pp;
            pp = p;
            p = ppp;
        }
        return pp;
    }
};

16.合并两个排序的链表

题目链接

题目描述:

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

解题思路

链表模拟 类似于归并排序

class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2){
        ListNode* p = new ListNode(0);
        ListNode* node = p;
        while(pHead1!=NULL&&pHead2!=NULL){
            if((pHead1->val)>(pHead2->val)){
                ListNode* pp = new ListNode(pHead2->val);
                p->next = pp;
                p = pp;
                pHead2 = pHead2->next;
            }else{
                ListNode* pp = new ListNode(pHead1->val);
                p->next = pp;
                p = pp;
                pHead1 = pHead1->next;
            }
        }
        while(pHead1!=NULL){
            ListNode* pp = new ListNode(pHead1->val);
            p->next = pp;
            p = pp;
            pHead1 = pHead1->next;
        }
        
        while(pHead2!=NULL){
            ListNode* pp = new ListNode(pHead2->val);
            p->next = pp;
            p = pp;
            pHead2 = pHead2->next;
        }
       return node->next;
    }
};

17.树的子结构

题目链接

题目描述:

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

解题思路

链表模拟 当节点相等的时候递归判断他的子节点是否相等

class Solution {
public:
    
    bool isOk(TreeNode* pRoot1, TreeNode* pRoot2){
        if(pRoot2==NULL) return 1;
        if(pRoot1==NULL) return 0;
        if(pRoot1->val!=pRoot2->val) return 0; 
        if(!isOk(pRoot1->left,pRoot2->left)){
            return 0;
        }
        if(!isOk(pRoot1->right,pRoot2->right)){
            return 0;
        }
        return 1;
    }
    
    bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2){
        bool fa = 0;
        if(pRoot1==NULL||pRoot2==NULL){
            return false;
        }
        if(pRoot1->val = pRoot2->val){
            if(isOk(pRoot1,pRoot2)){
                return true;
            }
        }
        if(HasSubtree(pRoot1->left,pRoot2)){
            return true;
        }
        if(HasSubtree(pRoot1->right,pRoot2)){
            return true;
        }
        return false;
    }
};

18.二叉树的镜像

题目链接

题目描述:

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

输入描述
二叉树的镜像定义:源二叉树 
        8
       /  \
      6   10
     / \  / \
    5  7 9 11
    镜像二叉树
        8
       /  \
      10   6
     / \  / \
    11 9 7  5
解题思路

递归求解

class Solution {
public:
    void Mirror(TreeNode *pRoot) {
        if(pRoot!=NULL){
            Mirror(pRoot->left);
            Mirror(pRoot->right);
            TreeNode* p = pRoot->left;
            pRoot->left = pRoot->right;
            pRoot->right = p;
        }
    }
};

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> q;
            int x = 0,y = matrix.size()-1;
            int xx= 0,yy = matrix[0].size()-1;
            while(x<=y&&xx<=yy){
               for(int j=xx;j<=yy;j++){
                  q.push_back(matrix[xx][j]);
               }

               for(int j=x+1;j<=y;j++){
                 q.push_back(matrix[j][yy]);
               }
               if(x<y)
               for(int j=yy-1;j>=xx;j--){
                 q.push_back(matrix[y][j]);
               }
               if(xx<yy)
               for(int j=y-1;j>x;j--){
                 q.push_back(matrix[j][xx]);
               }
               xx++,x++,y--,yy--;
            }
            return q;

        }
    };

20.包含min函数的栈

题目链接

题目描述:

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

解题思路

用两个栈 一个栈保存数据,另一个栈记录当前的最小值

    class Solution {
public:
    std::stack<int>st1;
    std::stack<int>st2;
    void push(int value) {
        st1.push(value);
        if(st2.empty()){
            st2.push(value);
        }else{
            int mi = st2.top();
            mi = std::min(value,mi);
            st2.push(mi);
        }
    }
    void pop() {
        if(!st1.empty()){
            st1.pop();
            st2.pop();
        }
    }
    int top() {
        return st1.top();
    }
    int min() {
        return st2.top();
    }
};

21.栈的压入、弹出序列

题目链接

题目描述:

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

解题思路

我们用一个栈保存一下入栈的顺序,每次比较一下栈顶和popV当前的数是否相等,相等的话就删除栈顶,然后将popV向前推进一格,如果不想当的话就接着入栈直到相等,如果全部入栈,栈顶和popV当前的数还不相等说明不符合

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

                st.push(pushV[ll++]);
            }else if(st.top()!=popV[l]) return false;
            else return false;
        }
        return true;
    }
};

22.从上往下打印二叉树

题目链接

题目描述:

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

解题思路

层次遍历,整一个队列就好了 bfs

class Solution {
public:
    vector<int> PrintFromTopToBottom(TreeNode* root) {
        std:: queue<TreeNode* > Q;
        std::vector<int>q;
        if(root==NULL) return q;
        Q.push(root);
        while(!Q.empty()){
            TreeNode* p = Q.front();
            Q.pop();
            if(p!=NULL) q.push_back(p->val);
            if(p->left!=NULL){
                Q.push(p->left);
            }
            if(p->right!=NULL){
                Q.push(p->right);
            }
        }
        return q;
    }
};

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

题目链接

题目描述:

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

解题思路

我们知道二叉搜索树的性质就是左子树小于当前节点,右子树大于当前节点,所以我们先找到左右子树的边界,然后进行判断是否满足二叉搜索树的性质,然后递归两个子树即可

class Solution {
public:
    bool check(vector<int> sequence,int l,int r){
        if(l>=r) return true;
        int i = r-1;
        while(i>=l&&sequence[i]>sequence[r]) i--;
        for(int j=l;j<=i;j++) if(sequence[j]>sequence[r]) return false;
        //cout<<l<<" "<<i<<" "<<r-1<<endl;
        return check(sequence,l,i)&&check(sequence,i+1,r-1);
    }
    bool VerifySquenceOfBST(vector<int> sequence) {
       if(sequence.size()<=0) return false;
       return check(sequence,0,sequence.size()-1);
    }
};

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

题目链接

题目描述:

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

解题思路

dfs 如果超过了 想要的 直接剪枝 一直搜到叶子节点 复杂度 O(n)

class Solution {
public:
    
   static bool cmp(vector<int>q,vector<int>w){
      return q.size()>w.size();
    }
    
    vector<vector<int> > Q;
    void dfs(TreeNode* root,int sum,vector<int> q,int ans){       
        if(root==NULL) return ;
        sum+=root->val;
        if(sum>ans) return ;
        q.push_back(root->val);
       
       dfs(root->left,sum,q,ans);
       dfs(root->right,sum,q,ans);
         if(sum==ans&&root->left==NULL&&root->right==NULL){
          Q.push_back(q);
          return ;
        }
    }
    vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
        vector<int>q;
        if(root==NULL) return Q;
        dfs(root,0,q,expectNumber);
        sort(Q.begin(),Q.end(),cmp);
        return Q;
    }
};

25.复杂链表的复制

题目链接

题目描述:

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

解题思路

先把整个链表复制下来,然后我们从头开始遍历,如果random不是空的话,我们就从头开始找,找到之后直接加上去就完事了

class Solution {
public:
    RandomListNode* Clone(RandomListNode* pHead){
        RandomListNode* p=new RandomListNode(0);
        RandomListNode* pp = p;
        RandomListNode* head = pHead;
        while(head!=NULL){
           RandomListNode* node = new RandomListNode(head->label);
           p->next = node;
           p = node;
           head = head->next;
        }
        head = pHead;
        p = pp->next;
        while(head!=NULL&&p!=NULL){
           if(head->random!=NULL){ // random 不是空
               RandomListNode* node =pHead;  // 然后找到两个链表的开头开始遍历
               RandomListNode* node1 = pp->next;
               while(head->random!=node&&node!=NULL&&node1!=NULL){
                  node = node->next;
                  node1 = node1->next;
               }
               p->random = node1; //找到之后复制一下
           }
           p = p->next;
           head = head->next;
        }
        return pp->next;
    }
};

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

题目链接

题目描述:

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

解题思路

先利用中序遍历然后把二叉树搞成一条有序的链表,然后在依次搞定left

class Solution {
public:
    TreeNode* p = new TreeNode(0); // 链表的头结点
    TreeNode* pp = p;
    void dfs(TreeNode* root){   //中序遍历
        if(root==NULL) return ;
        dfs(root->left);
        TreeNode* node = new TreeNode(root->val);
        p->right = node;
        p = node;
        dfs(root->right);
    }
    TreeNode* Convert(TreeNode* pRootOfTree){
        dfs(pRootOfTree);
        p = pp->right;
        TreeNode* node = pp;
        while(p!=NULL){             // 搞定 left
            p->left = node;
            p = p->right;
            node = node->right;
        }
        if(pp->right!=NULL)   //将实际的头结点的左侧设置为NULL
            pp->right->left = NULL;
        return pp->right;
    }
};

27.字符串的排列

题目链接

题目描述:

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

解题思路

c++ 利用了stl 的全排列 搞定,也可以用爆搜解决

class Solution {
public:
    vector<string> Permutation(string str) {
        
        vector<string>q;
        if(str.size()==0) return q;
        int l =str.size();
         do{
            q.push_back(str);
        }while (std::next_permutation(str.begin(),str.end()));
        return q;
    }
};

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

题目链接

题目描述:

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

解题思路

map 存一下

class Solution {
public:
    int MoreThanHalfNum_Solution(vector<int> numbers) {
        std::map<int,int>mp;
        int len = numbers.size();
        for(int j=0;j<len;j++){
            mp[numbers[j]]++;
            if(mp[numbers[j]]>len/2) return numbers[j];
        }
        return 0;
    }
};

29.最小的K个数

题目链接

题目描述:

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

解题思路

c++ stl 的优先队列 先入队 当 堆顶的元素大于当前的数时 弹出,把当前的数加入堆中即可

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
       vector<int>q;
       if(k>input.size()) return q;
       // priority_queue<int,vectot<int>,greater<int> > 小根堆
       std::priority_queue<int>Q; // 默认大根堆
       for(int j=0;j<input.size();j++){
           if(Q.size()<k){
               Q.push(input[j]);
           }else{
               if(!Q.empty()&&Q.top()>input[j]){
                   Q.pop();
                   Q.push(input[j]);
               }
           }
       }
        while(!Q.empty()){
            q.push_back(Q.top());
            Q.pop();
        }
        return q;
    }
};

30.连续子数组的最大和

题目链接

题目描述:

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

解题思路

这个题就是算每个数的贡献度,我们想要最大的和就是要每个数贡献最大的,只要有整数我们就累加,一旦他变成负数说明对结果产生负贡献,我们就把他舍弃掉就好了

class Solution {
public:
    int FindGreatestSumOfSubArray(vector<int> array) {
        int mx = -(int)1e9,ans = 0;
        for(int j=0;j<array.size();j++){
            ans += array[j];
            mx = max(mx,ans);
            if(ans<0) ans = 0;
        }
        return mx;
    }
};

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){
        int ans = 0;
        for(int j=1;j<=n;j*=10){
           ans = ans+n/(j*10)*j;
           if((n%(j*10))>=j+j-1){
             ans += j;
           }else if((n%(j*10))<j){
              continue;
           }else{
              ans += n%(j*10)-j+1;
           }
        }
        return ans;
    }
};

32.把数组排成最小的数

题目链接

题目描述:

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

解题思路

自定义排序

class Solution {
public:
   bool static cmp (string q,string w){
      return q+w<w+q;
   }
    string PrintMinNumber(vector<int> numbers) {
        std::vector<string> s;
        for(int j=0;j<numbers.size();j++){
            s.push_back(to_string(numbers[j]));
        }
        sort(s.begin(),s.end(),cmp);
        string ans;
        for(int j=0;j<s.size();j++){
          ans+=s[j];
        }
        return ans;
    }
};

33.丑数

题目链接

题目描述:

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

解题思路

点击这里

class Solution {
public:
    int GetUglyNumber_Solution(int index) {
        int i = 0, ii = 0, iii = 0, mi = 1;
        vector<int> q;
        q.push_back(mi);
        while(q.size() < index) {
            int mi = min(q[i] * 2, min(q[ii] * 3, q[iii] * 5));
            if(q[i] * 2 == mi) i++;
            if(q[ii] * 3 == mi) ii++;
            if(q[iii] * 5 == mi) iii++;
            q.push_back(mi);
        }
        return mi;
    }
};

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

题目链接

题目描述:

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

解题思路
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;
    }
};

35.数组中的逆序对

题目链接

题目描述:

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

输入描述

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

解题思路

归并排序

class Solution {
public:
    int ans = 0;
    int a[2*100005];
    void mem(int l,int r,vector<int>& data){
        if(r-l>0){
           int mid = (l+r)/2;
           mem(l,mid,data);
           mem(mid+1,r,data);
        }
        int mid = (l+r)/2;
        int L=l,m = mid+1,i=0;
        while(L<=mid&&m<=r){
           if(data[L]<=data[m]){
              a[i++] = data[L++];
           }else{
              a[i++] = data[m];
              ans += mid-L+1;
              ans = ans%1000000007;
              m++;
           }
        }
        while(L<=mid){
          a[i++] = data[L++];
        }
        while(m<=r){
          a[i++] = data[m++];
        }
        for(int j=0;j<i;j++){
           data[j+l] = a[j];
        }
    }
 
    int InversePairs(vector<int> data) {
         mem(0,data.size()-1,data);
         return ans;
    }
};

36.两个链表的第一个公共结点

题目链接

题目描述:

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

输入描述
解题思路

暴力

class Solution {
public:
    ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
        ListNode* p = pHead1;
        //ListNode* head = pHead2;
        ListNode* ans = NULL ;
        while(p!=NULL){
           ListNode* head = pHead2;
           bool fa = 0;
           while(head!=NULL){
              if(head == p){
                 ans = p;
                 fa=1;
                 break;
              }
              head = head->next;
           }
           p = p->next;
           if(fa){
             break;
           }
        }
        return ans;
    }
};

37.数字在排序数组中出现的次数

题目链接

题目描述:

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

输入描述
解题思路

既然是有序数组,就可以利用二分找到相应的位置

class Solution {
public:
    int GetNumberOfK(vector<int> data ,int k) {
        if(data.size()==0) return 0;
        int l = std::lower_bound(data.begin(),data.end(),k)-data.begin();
        int r = std::lower_bound(data.begin(),data.end(),k+1)-data.begin();
        if(data[r-1]!=data[l]) return 0;
        return r-l;
    }
};

38.二叉树的深度

题目链接

题目描述:

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

输入描述
解题思路
class Solution {
public:
    int TreeDepth(TreeNode* pRoot)
    {
        if(pRoot==NULL){
            return 0;
        }
        return 1+std::max(TreeDepth(pRoot->left),TreeDepth(pRoot->right));
    }
};

39.平衡二叉树

题目链接

题目描述:

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

输入描述
解题思路
class Solution {
public:
    bool fa = 0;
    int work(TreeNode* pRoot){
      if(pRoot==NULL) return 0;
      int l = work(pRoot->left);
      int r = work(pRoot->right);
      if(abs(l-r)>1){
         fa=1;
      }
      return max(l,r)+1;
    }
    bool IsBalanced_Solution(TreeNode* pRoot) {
        work(pRoot);
        if(fa) return false;
        return true;
    }
};

40.数组中只出现一次的数字

题目链接

题目描述:

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

输入描述
解题思路

解题思路

class Solution {
public:
    void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
       int res = 0;
       for(int j=0;j<data.size();j++){
          res^=data[j];
       }
       int i = 0;
       for(int j=0;j<32;j++){
          if((res>>j)&1){
             i = j;
             break;
          }
       }
       *num1 = 0,*num2 = 0;
       for(int j=0;j<data.size();j++){
          if(data[j]&(1<<i)){
             *num1^=data[j];
          }else{
             *num2^=data[j];
          }
       }
    }
};

41.和为S的连续正数序列

题目链接

题目描述:

小明很喜欢数学,有一天他在做数学作业时,要求计算出9-16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!

输入描述

输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序

解题思路

利用尺取法

class Solution {
public:
    vector<vector<int> > FindContinuousSequence(int sum) {
       int l = 1,r = 2;
       vector<vector<int> >Q;
       while(r<=sum&&l<r){
          int res = (r-l+1)*(l+r)/2;
          if(res<sum){
               r++;
          }else if(res>sum){
            l++;
          }else{
             vector<int>q;
             for(int j=l;j<=r;j++){
                q.push_back(j);
             }
             Q.push_back(q);
             q.clear();
            l++;
          }
       }
       return Q;
    }
};

42.和为S的连续正数序列

题目链接

题目描述:

输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。

输入描述

对应每个测试案例,输出两个数,小的先输出。

解题思路

既然是有序,我们就从两边逼近,并且两个数距离越远乘积越小

class Solution {
public:
    vector<int> FindNumbersWithSum(vector<int> array,int sum) {
        vector<int>q;
        int l = 0,r =array.size()-1;
        while(l<r){
            if(array[l]+array[r]>sum){
                r--;
            }else if(array[l]+array[r]<sum){
                l++;
            }else{
                q.push_back(array[l]);
                q.push_back(array[r]);
                break;
            }
        }
        return q;
    }
};

43.左旋转字符串

题目链接

题目描述:

汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它

输入描述
解题思路

stl

class Solution {
public:
    string LeftRotateString(string str, int n) {
        if(n<0) return NULL;
        if(n==0) return str;
        string strTemp="";
          
          strTemp=str.substr(0,n);
          str.erase(0,n);
         str+=strTemp;
        return str;
        
    }
};

44.翻转单词顺序列

题目链接

题目描述:

牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

输入描述
解题思路

stl

class Solution {
public:
    string ReverseSentence(string str) {
        string res = "",st="";
        str+=" ";
        for(int j=0;j<str.size();j++){
           if(str[j]==' '){
              res+=" ";
              reverse(st.begin(),st.end());
              res+=st;
              st="";
           }else{
              st+=str[j];
           }
        }
        reverse(res.begin(),res.end());
        res.erase(str.size()-1,str.size());
        return res;
    }
};

45.扑克牌顺子

题目链接

题目描述:

LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张)
他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。

输入描述
解题思路

stl

class Solution {
public:
    bool IsContinuous( vector<int> numbers ) {
        if(numbers.size()<5) return false;
        int mp[14]={0},mi = 14,mx = 0;
        for(int j=0;j<numbers.size();j++){
            mp[numbers[j]]++;
            if(numbers[j]==0) continue;
            if(mp[numbers[j]]>1) return false;
            mi = std::min(mi,numbers[j]);
            mx = std::max(mx,numbers[j]);
            if(mx-mi>=5) return false;
        }
        return true;
    }
};

46.孩子们的游戏(圆圈中最后剩下的数)

题目链接

题目描述:

每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!\^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)

输入描述
解题思路

约瑟夫环经典问题

class Solution {
public:
    bool IsContinuous( vector<int> numbers ) {
        if(numbers.size()<5) return false;
        int mp[14]={0},mi = 14,mx = 0;
        for(int j=0;j<numbers.size();j++){
            mp[numbers[j]]++;
            if(numbers[j]==0) continue;
            if(mp[numbers[j]]>1) return false;
            mi = std::min(mi,numbers[j]);
            mx = std::max(mx,numbers[j]);
            if(mx-mi>=5) return false;
        }
        return true;
    }
};

47.求1+2+3+...+n

题目链接

题目描述:

求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

输入描述
解题思路
class Solution {
public:
    int Sum_Solution(int n) {
        int ans = n;
        bool fa = ans && (ans += Sum_Solution(n - 1));
        return ans;
    }
};

48.不用加减乘除做加法

题目链接

题目描述:

写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

输入描述
解题思路
class Solution {
public:
    int Add(int num1, int num2){
        int x = num1,y = num2;
        while(x&y){
            num1 = x,num2 = y;
            x = (num1&num2)<<1;
            y = num1^num2;
        }
        return x|y;
    }
};

49.把字符串转换成整数

题目链接

题目描述:

将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0。

输入描述
解题思路
class Solution {
public:
    int StrToInt(string str) {
        int ans = 0;
        if(str.size()==0) return 0;
        for(int j=0;j<str.size();j++){
           if(str[j]>='0'&&str[j]<='9'){
              int i = str[j]-'0';
              ans = ans*10+i;
           }
        }
        for(int j=1;j<str.size()-1;j++){
           if(str[j]>='0'&&str[j]<='9'){
              continue;
           }else return 0;
        }
        if(str[0]=='-') ans = -ans;
        return ans;
    }
};

50.数组中重复的数字

题目链接

题目描述:

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

输入描述
解题思路
class Solution {
public:
    // Parameters:
    //        numbers:     an array of integers
    //        length:      the length of array numbers
    //        duplication: (Output) the duplicated number in the array number
    // Return value:       true if the input is valid, and there are some duplications in the array number
    //                     otherwise false
    bool duplicate(int numbers[], int length, int* duplication) {
        std::map<int,int>mp;
        *duplication = -1;
        for(int j=0;j<length;j++){
            mp[numbers[j]]++;
            if(mp[numbers[j]]>=2){
                *duplication = numbers[j];
                return 1;
            }
        }
        return false;
    }
};
//
dalao们的解法 On 空间复杂度 O1 tql orz
bool duplicate(int numbers[], int length, int* duplication) {
    for(int i=0;i!=length;++i){
        int index=numbers[i]%length;
        if(numbers[index]>=length){
            *duplication=index;
            return 1;
        }              
        numbers[index]+=length;  
    }
    return 0;
}

51.构建乘积数组

题目链接

题目描述:

给定一个数组A[0,1,...,n-1],请构建一个数组B[0,1,...,n-1],其中B中的元素B[i]=A[0]*A[1]*...*A[i-1]*A[i+1]*...*A[n-1]。不能使用除法。

输入描述
解题思路
class Solution {
public:
    vector<int> multiply(const vector<int>& A) {
        vector<int> b(A.size());
        int res=1;
        for(int i=0;i<A.size();res*=A[i++]){
            b[i]=res;
        }
        res=1;
        for(int i=A.size()-1;i>=0;res*=A[i--]){
            b[i]*=res;
        }
        return b;
    }
};

52.正则表达式匹配

题目链接

题目描述:

请实现一个函数用来匹配包括'.'和''的正则表达式。模式中的字符'.'表示任意一个字符,而''表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配

输入描述
解题思路
class Solution {
public:
    bool match(char* str, char* pattern){
       if(*str=='\0'&&*pattern=='\0') return 1;
       if(*str!='\0'&&*pattern=='\0') return 0;
       if (*(pattern+1) != '*'){
          if (*str == *pattern || (*str != '\0' && *pattern == '.'))
              return match(str+1, pattern+1);
          else
              return 0;
       }else{
          if (*str == *pattern || (*str != '\0' && *pattern == '.'))
              return match(str, pattern+2) || match(str+1, pattern);
          else
              return match(str, pattern+2);
      }
    }
};

53.表示数值的字符串

题目链接

题目描述:

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。

输入描述
解题思路
class Solution {
public:
    bool isNumeric(char* strings){
       bool fa = 0; // 看符号前面是否有数字
       int f = 0,i=0;
       int len = strlen(strings);
       // 判断开头
       if(len==0) return 0;
       if(strings[i]=='+'||strings[i]=='-'){
          i++;
       }
       while(i<len){
          // 如果开头是数字的话就continue
          if(f==0&&strings[i]>='0'&&strings[i]<='9'){
              i++; fa=1;
              continue;
          }
          if(strings[i]=='e'||strings[i]=='E'){
            if(!fa) return 0;
            if(f==1) return 0;
            f = 1,i++;
            if(i!=len&&(strings[i]!='-'||strings[i]!='+')&&strings[i+1]>='0'&&strings[i+1]<='9'){
               i++; // 判断 1e-1这种情况
            }else if(i!=len&&strings[i]>='0'&&strings[i]<='9'){
               i++; // 判断 1e1这种情况
            }else return 0;
          }else if(strings[i]=='.'){
             if(f) return 0; //判断小数点前面是否会出现 E/e/. 的情况
             f = 2,i++;
             if(i==len&&(strings[i]>'9'||strings[i]<'0')){
                return 0; // 判断后面必须有数
             }else i++;
          }else if(strings[i]=='+'||strings[i]=='-'){
              return 0; //中间遇到+- 都是不符合情况的
          }else if(strings[i]>='0'&&strings[i]<='9'){
             i++;//中间遇到数字就略过
          }else return 0;
       }
       return 1;
    }
};

54.字符流中第一个不重复的字符

题目链接

题目描述:

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"

输入描述
解题思路
class Solution{
    public:
    
    string s;
    std::map<char,int>mp;
    void Insert(char ch){
        s+=ch;
        mp[ch]++;
    }
    char FirstAppearingOnce(){
         
        int len=s.size();
        for(int i=0;i<len;i++)
        {
            if(mp[s[i]]==1)
                return s[i];
        }
        return '#';
    }
 
};

55.链表中环的入口结点

题目链接

题目描述:

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

输入描述
解题思路

两个指针 一个每次前进一步,另一个每次前进两步。重合之后,另一个从头开始,然后每次前进一步,相遇就是入口。

class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead){
        ListNode* p1 = pHead;
        ListNode* p2 = pHead;
        if(pHead==NULL||p2->next==NULL) return NULL;
        while(p1!=NULL&&p2->next!=NULL){
           p1 = p1->next;
           p2 = p2->next->next;
           if(p1==p2){
              break;
           }
        }
        p2 = pHead;
        while(p2!=p1){
           p2 = p2->next;
           p1 = p1->next;
        }
        if(p2==p1&&p1!=NULL) return p1;
        return NULL;

    }
};

56.删除链表中重复的结点

题目链接

题目描述:

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

输入描述
解题思路

先把重复的节点标记一下,然后去除标记节点就好了


class Solution {
public:
    ListNode* deleteDuplication(ListNode* pHead){
        if(pHead==NULL||pHead->next==NULL) return pHead;
        ListNode* p = pHead;
        ListNode* pn = pHead->next;
        // 把重复的节点都标记为-1
        while(p!=NULL&&pn!=NULL){
           bool fa=0;
           while(pn!=NULL&&p!=NULL&&p->val==pn->val){
              fa = 1;
               pn = pn->next;
           }
           if(p!=NULL){
               if(fa) p->val = -1;
               p ->next = pn;
               p = p->next;
               if(pn!=NULL) pn = pn->next;
            }else{
               p->next=NULL;
           }
        }
        
        //去除-1的节点
        while(pHead!=NULL&&pHead->val == -1){
            pHead = pHead->next;
        }
        p = pHead;
        while(p!=NULL){
            if(p->next!=NULL&&p->next->val == -1){
                pn = p->next;
                while(pn!=NULL&&pn->val==-1){
                    pn = pn->next;
                }
                p->next = pn;
                if(p!=NULL)
                p = p->next;
            }else p = p->next;
        }
        return pHead;
    }
};

57.二叉树的下一个结点

题目链接

题目描述:

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

输入描述
解题思路
class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode){
        if(pNode==NULL) return pNode;
        if(pNode->right!=NULL){
            pNode = pNode->right;
            while(pNode->left!=NULL){
                pNode = pNode->left;
            }
            return pNode;
        }
        while(pNode->next!=NULL){
            TreeLinkNode *p= pNode->next;
            if(p->left==pNode) return p;
            pNode = pNode->next;
        }
        return NULL;
    }
};

58.对称的二叉树

题目链接

题目描述:

请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

输入描述
解题思路
class Solution {
public:
    bool check(TreeNode* left,TreeNode* right){
        if(left==NULL&&right==NULL) return 1;
        if(left==NULL&&right!=NULL||left!=NULL&&right==NULL) return 0;
        if(left->val!=right->val) return 0;
        return check(left->left,right->right)&&check(left->right,right->left);
    }
    bool isSymmetrical(TreeNode* pRoot){
        if(pRoot==NULL) return 1;
        return check(pRoot->left,pRoot->right);
    }

};

59.按之字形顺序打印二叉树

题目链接

题目描述:

请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

输入描述
解题思路

利用两个栈,模拟一下

class Solution {
public:
    std::stack<TreeNode*>st1;
    std::stack<TreeNode*>st2;
    vector<vector<int> > Print(TreeNode* pRoot) {  
        vector<vector<int> >Q;
        if(pRoot==NULL) return Q;
         st1.push(pRoot);
        while(st1.size()>0||st2.size()>0){
            vector<int>q;
            if(st1.size()>0){
                while(!st1.empty()){
                    TreeNode* p = st1.top();
                    q.push_back(p->val);
                    st1.pop();
                    if(p->left!=NULL) st2.push(p->left);
                    if(p->right!=NULL) st2.push(p->right);
                }
                Q.push_back(q);
            }else{
                while(!st2.empty()){
                    TreeNode* p = st2.top();
                    q.push_back(p->val);
                    st2.pop();
                    if(p->right!=NULL) st1.push(p->right);
                    if(p->left!=NULL) st1.push(p->left);
                }
                Q.push_back(q);
            }
        }
        return Q;
    }
    
};

60.把二叉树打印成多行

题目链接

题目描述:

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

输入描述
解题思路

和上个题基本一样,只用翻转一下就好了,或者用一个队列解决

class Solution {
public:
    std::stack<TreeNode*>st1;
    std::stack<TreeNode*>st2;
    vector<vector<int> > Print(TreeNode* pRoot) {
       
        vector<vector<int> >Q;
        if(pRoot==NULL) return Q;
         st1.push(pRoot);
        while(st1.size()>0||st2.size()>0){
            vector<int>q;
            if(st1.size()>0){
                while(!st1.empty()){
                    TreeNode* p = st1.top();
                    q.push_back(p->val);
                    st1.pop();
                    if(p->left!=NULL) st2.push(p->left);
                    if(p->right!=NULL) st2.push(p->right);
                }
               
                Q.push_back(q);
            }else{
                while(!st2.empty()){
                    TreeNode* p = st2.top();
                    q.push_back(p->val);
                    st2.pop();
                    if(p->right!=NULL) st1.push(p->right);
                    if(p->left!=NULL) st1.push(p->left);
                }
                reverse(q.begin(),q.end());
                Q.push_back(q);
            }
        }
        return Q;
    }
    
};

61.序列化二叉树

题目链接

题目描述:

请实现两个函数,分别用来序列化和反序列化二叉树

输入描述
解题思路

留着以后补

链接:https://www.nowcoder.com/questionTerminal/cf7e25aa97c04cc1a68c8f040e71fb84
来源:牛客网

typedef TreeNode node;
typedef TreeNode* pnode;
typedef int* pint;
class Solution {
    vector<int> buf;
    void dfs(pnode p){
        if(!p) buf.push_back(0x23333);
        else{
            buf.push_back(p -> val);
            dfs(p -> left);
            dfs(p -> right);
        }
    }
    pnode dfs2(pint& p){
        if(*p == 0x23333){
            ++p;
            return NULL;
        }
        pnode res = new node(*p);
        ++p;
        res -> left = dfs2(p);
        res -> right = dfs2(p);
        return res;
    }
public:
    char* Serialize(TreeNode *p) {
        buf.clear();
        dfs(p);
        int *res = new int[buf.size()];
        for(unsigned int i = 0; i < buf.size(); ++i) res[i] = buf[i];
        return (char*)res;
    }
    TreeNode* Deserialize(char *str) {
        int *p = (int*)str;
        return dfs2(p);
    }
};

62.二叉搜索树的第k个结点

题目链接

题目描述:

给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。

输入描述
解题思路
class Solution {
public:
    int i = 0;
    TreeNode* KthNode(TreeNode* pRoot, int k){
        if(pRoot == NULL) return NULL;
        
        TreeNode* p = KthNode(pRoot->left, k);
        i++;
        if(p!=NULL) return p;
        if(i==k) return pRoot;
        if(i<k) return KthNode(pRoot->right,k);
        return NULL;
    }

    
};

63.数据流中的中位数

题目链接

题目描述:

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

输入描述
解题思路
class Solution {
public:
    priority_queue<int, vector<int>, less<int> > p;
    priority_queue<int, vector<int>, greater<int> > q;
    void Insert(int num){
        if(p.empty() || num <= p.top()) p.push(num);
        else q.push(num);
        if(p.size() == q.size() + 2) q.push(p.top()), p.pop();
        if(p.size() + 1 == q.size()) p.push(q.top()), q.pop();
    }
    double GetMedian(){ 
      return p.size() == q.size() ? (p.top() + q.top()) / 2.0 : p.top();
    }
};

64.滑动窗口的最大值

题目链接

题目描述:

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。

输入描述
解题思路

经典问题

class Solution {
public:
    vector<int> maxInWindows(const vector<int>& num, unsigned int size){
        std::vector<int>q;
        std::deque<int>Q;
        for(int j=0;j<num.size();j++){
            while(Q.size()>0&&num[j]>=num[Q.back()]){
                Q.pop_back();
            }
            while(Q.size()>0&&(j-Q.front()+1)>size){
                Q.pop_front();
            }
            Q.push_back(j);
            if(size>0&&j+1>=size){
                q.push_back(num[Q.front()]);
            }
        }
        return q;
    }
};

65.矩阵中的路径

题目链接

题目描述:

请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。

输入描述
解题思路

dfs

class Solution {
public: 
    bool dfs(char* matrix, int rows, int cols, char* str,int i,int j){
        if (!str || !(*str))
            return true;
        bool ans=false;
        if ((i>=0) && (i<rows) && (j>=0) && (j<cols) && (matrix[i*cols+j]== *str)){
            matrix[i*cols+j]='\0';
            ans=dfs(matrix, rows, cols, str+1, i-1, j)|| dfs(matrix, rows, cols, str+1, i+1, j)|| dfs(matrix, rows, cols, str+1, i, j-1)|| dfs(matrix, rows, cols, str+1, i, j+1);
            matrix[i*cols+j]=*str;
        }
        return ans;
    }
     
     
    bool hasPath(char* matrix, int rows, int cols, char* str){
        for (int i=0;i<rows;i++){
            for (int j=0;j<cols;j++){
                if(dfs(matrix, rows, cols, str, i, j)){
                    return true;
                }
            }
        }
        return false;
     
    }
};

66.机器人的运动范围

题目链接

题目描述:

地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

输入描述
解题思路

dfs

const int maxn=100;
int dx[]={0,1,0,-1},dy[]={1,0,-1,0};     
int fa[maxn][maxn]={0};    
int sum;     
class Solution {
public:
    void dfs(int x,int y,int k,int m,int n){
        fa[x][y]=1;
        for(int i=0;i<=3;++i){
            int xx=x+dx[i],yy=y+dy[i];
            if(fa[xx][yy]==0&&xx>=0&&xx<m&&yy>=0&&yy<n&&(xx%10+xx/10+yy%10+yy/10<=k)){
                ++sum;
                dfs(xx,yy,k,m,n);
            }
        }
    }
    int movingCount(int k, int rows, int cols){
        if(k<0) return 0;
        memset(fa,0,sizeof(fa));
        sum=1;
        dfs(0,0,k,rows,cols);
        return sum;   
    }
};

转载于:https://www.cnblogs.com/DyLoder/p/10976101.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值