zoukankan      html  css  js  c++  java
  • 剑指Offer全解

    二维数组中的查找

    描述

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

    源码

    public class Solution {
        public boolean Find(int target, int [][] array) {
            if(array.length==0 || array[0].length==0){
                return false;
            }
            
            int row = 0,col = 0;
            for(int i=0;i<array[0].length;i++){
                if(array[0][i]<target){
                    col = i;
                }else{
                    break;
                }
            }
            for(int i=0;i<array.length;i++){
                if(array[i][col]<target){
                    row = i;
                }else{
                    break;
                }
            }
            for(int i=row;i<array.length;i++){
                for(int k=0;k<=col;k++){
                    if(array[i][k]==target){
                        return true;
                    }
                }
            }
            return false;
        }
    }
    

    替换空格

    描述

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

    源码

    public class Solution {
        public String replaceSpace(StringBuffer str) {
            int wsCnt = 0;
            for(int i=0;i<str.length();i++){
                if(str.charAt(i)==' '){
                    wsCnt++;
                }
            }
            int oldLen = str.length();
            str.setLength(wsCnt*2+str.length());
            for(int i=oldLen-1;i>=0;i--){
                if(str.charAt(i)!=' '){
                    str.setCharAt(i+wsCnt*2,str.charAt(i));
                }else{
                    str.setCharAt(i+wsCnt*2,'0');
                    str.setCharAt(i+wsCnt*2-1,'2');
                    str.setCharAt(i+wsCnt*2-2,'%');
                    wsCnt--;
                }
            }
            return str.toString();
        }
    }
    

    从尾到头打印链表

    描述

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

    源码

    import java.util.ArrayList;
    public class Solution {
        public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
            ArrayList<Integer> list = new ArrayList<>();
            if(listNode==null){
                return list;
            }
            while(listNode!=null){
                list.add(0,listNode.val);
                listNode=listNode.next;
            }
            return list;
        }
    }
    

    重建二叉树

    描述

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

    源码

    /**
     * Definition for binary tree
     * public class TreeNode {
     *     int val;
     *     TreeNode left;
     *     TreeNode right;
     *     TreeNode(int x) { val = x; }
     * }
     */
    public class Solution {
        public TreeNode subTree(int[] preOrder, int[] inOrder,
                               int preStart, int preEnd,
                               int inStart, int inEnd){
            if(preStart>=preEnd){
                return null;
            }
            // root val
            TreeNode t = new TreeNode(preOrder[preStart]);
            // find index of node value in inOrder array
            int pos = 0;
            for(int i=0;i<inOrder.length;i++){
                if(inOrder[i]==preOrder[preStart]){
                    pos = i;
                    break;
                }
            }
            // left and right
            t.left = subTree(preOrder,inOrder,
                             preStart+1,preStart+1+(pos-inStart),
                            inStart,pos);
            t.right = subTree(preOrder,inOrder,
                             preStart+1+(pos-inStart),preEnd,
                             pos+1,inEnd);
            return t;
        }
        
        public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
            return subTree(pre,in,0,pre.length,0,in.length);
        }
    }
    

    用两个栈实现队列

    描述

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

    源码

    import java.util.Stack;
    
    public class Solution {
        Stack<Integer> stack1 = new Stack<Integer>();
        Stack<Integer> stack2 = new Stack<Integer>();
        
        public void push(int node) {
            stack1.push(node);
        }
        
        public int pop() {
            if(!stack2.isEmpty()){
                return stack2.pop();
            }else{
                while(stack1.size()!=1){
                    int val = stack1.pop();
                    stack2.push(val);
                }
                return stack1.pop();
            }
        }
    }
    

    旋转数组的最小数字

    描述

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

    源码

    import java.util.ArrayList;
    public class Solution {
        public int minNumberInRotateArray(int [] array) {
            if(array.length<=1){
                return array.length;
            }
            for(int i=1;i<array.length;i++){
                if(array[i]<array[0]){
                    return array[i];
                }
            }
            return 0;
        }
    }
    

    斐波那契数列

    描述

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

    源码

    public class Solution {
        public int Fibonacci(int n) {
            if(n<=1){
                return n>=0?n:0;
            }
            int a = 0,b=1,c=1;
            for(int i=2;i<=n;i++){
                c = a+b;
                a = b;
                b = c;
            }
            return c;
        }
    }
    

    跳台阶

    描述

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

    源码

    public class Solution {
        public int JumpFloor(int target) {
            int a=1,b=2,c=3;
            if(target<=3){
                return target>0?target:0;
            }
            for(int i=c;i<=target;i++){
                c = a + b;
                a = b;
                b = c;
            }
            return c;
        }
    }
    

    变态跳台阶

    描述

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

    源码

    public class Solution {
        public int JumpFloorII(int target) {
            return 1<<(target-1);
        }
    }
    

    矩形覆盖

    描述

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

    源码

    public class Solution {
        public int RectCover(int target) {
            int a=1,b=2,c=3;
            if(target<=3){
                return target>0?target:0;
            }
            for(int i=c;i<=target;i++){
                c = a + b;
                a = b;
                b = c;
            }
            return c;
        }
    }
    

    二进制中1的个数

    描述

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

    源码

    class Solution {
        public int NumberOf1(int n) {
             int cnt = 0;
             while(n!=0){
                 cnt++;
                 // 把一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0
                 n = n&(n-1);
             }
             return cnt;
         }
    }
    

    数值的整数次方

    描述

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

    源码

    public class Solution {
        public double Power(double base, int exponent) {
            boolean flag = false;
            if(exponent==0 && base!=0){
                return 1.0;
            }
            if(base==0){
                return 0;
            }
            
            double res = 1.0;
            for(int i=0;i<Math.abs(exponent);i++){
                res *=base;
            }
            return exponent>0?res:1/res;
      }
    }
    

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

    描述

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

    源码

    class Solution {
    public:
        void reOrderArray(vector<int> &array) {
            int cnt = 0;
            for(int i=0;i<array.size();i++){
                if(array[i]%2==1){
                    int p = i;
                    while(p>cnt){
                        int t = array[p];
                        array[p]=array[p-1];
                        array[p-1]=t;
                        p--;
                    }
                    cnt++;
                }
            }
        }
    };
    

    链表中倒数第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) {
            // 1-2-3-4
            if(pListHead==nullptr || k==0){
                return nullptr;
            }
            
            ListNode* p1=pListHead,*p2=pListHead;
            int cnt = 0;
            while(p2 && cnt<k){
                p2 = p2->next;
                cnt++;
            }
            if(cnt!=k){
                return nullptr;
            }
            
            while(p2){
                p1=p1->next;
                p2=p2->next;
            }
            return p1;
        }
    };
    

    反转链表

    描述

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

    源码

    /*
    struct ListNode {
        int val;
        struct ListNode *next;
        ListNode(int x) :
                val(x), next(NULL) {
        }
    };*/
    class Solution {
    public:
        ListNode* ReverseList(ListNode* pHead) {
            if(pHead==nullptr){
                return nullptr;
            }
            
            ListNode* newHead = nullptr;
            while(pHead){
                ListNode*t = new ListNode(pHead->val);
                t->next = newHead;
                newHead = t;
                pHead=pHead->next;
            }
            return newHead;
        }
    };
    

    合并两个排序的链表

    描述

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

    源码

    /*
    struct ListNode {
        int val;
        struct ListNode *next;
        ListNode(int x) :
                val(x), next(NULL) {
        }
    };*/
    class Solution {
    public:
        ListNode* Merge(ListNode* pHead1, ListNode* pHead2){
            // 1->2->3->5
            // 2->3->4
            if(pHead1==nullptr&&pHead2!=nullptr){
                return pHead2;
            }else if(pHead1!=nullptr&&pHead2==nullptr){
                return pHead1;
            }else if(pHead1==nullptr&&pHead2==nullptr){
                return nullptr;
            }
            
            ListNode* newHead = nullptr;
            if(pHead1->val > pHead2->val){
                newHead = pHead2;
            }else{
                newHead = pHead1;
            }
            while(pHead1!=nullptr||pHead2!=nullptr){
                if(pHead1!=nullptr&&pHead2!=nullptr){
                    if(pHead1->val <= pHead2->val){
                        ListNode* cur = pHead1->next;
                        pHead1->next = pHead2;
                        pHead1 = cur;
                    }else{
                        ListNode* cur = pHead2->next;
                        pHead2->next = pHead1;
                        pHead2 = cur;
                    }
                }
                else if(pHead1!=nullptr && pHead2==nullptr){
                    pHead1 = pHead1->next;
                }
                else if(pHead2!=nullptr && pHead1==nullptr){
                    pHead2 = pHead2->next;
                }
            }
            return newHead;
            
        }
    };
    

    树的子结构

    描述

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

    源码

    /**
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;
    
        public TreeNode(int val) {
            this.val = val;
    
        }
    
    }
    */
    public class Solution {
        public boolean check(TreeNode a, TreeNode b){
            if(b==null){
                return true;
            }
            if(a==null){
                return false; 
            }
            if(a.val==b.val){
                return check(a.left,b.left)&&check(a.right,b.right);
            }
            return false;
        }
        
        public boolean HasSubtree(TreeNode root1,TreeNode root2) {
            if(root1 == null || root2 == null){
                return false;
            }
            if(root1.val==root2.val){
                boolean r = check(root1,root2);
                if(r){
                    return true;
                }
            }
            
            boolean res= HasSubtree(root1.left,root2);
            if(res){
                return true;
            }
            res = HasSubtree(root1.right,root2);
            if(res){
                return true;
            }
            return false;
        }
    }
    

    二叉树的镜像

    描述

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

    源码

    /**
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;
    
        public TreeNode(int val) {
            this.val = val;
        }
    }
    */
    public class Solution {
        public void Mirror(TreeNode root) {
            if(root==null){
                return;
            }
            TreeNode a = root.left;
            root.left = root.right;
            root.right = a;
            Mirror(root.left);
            Mirror(root.right);
        }
    }
    

    顺时针打印矩阵

    描述

    输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下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> v;
            if(matrix.size()==0||matrix[0].size()==0){
                return v; 
            }
            int i=0,j=0;
            int cnt = 0;
            int widthStart = 0;
            int widthEnd = matrix[0].size();
            int heightStart = 0;
            int heightEnd = matrix.size();
            while(cnt < matrix.size()*matrix[0].size()){
                while(j<widthEnd){
                    v.push_back(matrix[i][j]);
                    j++;
                    cnt++;
                }
                j--;
                i++;
                if(i>=heightEnd){
                    break;
                }
                while(i<heightEnd){
                    v.push_back(matrix[i][j]);
                    i++;
                    cnt++;
                }
                i--;
                j--;
                if(j<widthStart){
                    break;
                }
                while(j>=widthStart){
                    v.push_back(matrix[i][j]);
                    j--;
                    cnt++;
                }
                j++;
                i--;
                if(i<heightStart){
                    break;
                }
                while(i>=heightStart+1){
                    v.push_back(matrix[i][j]);
                    i--;
                    cnt++;
                }
                i++;
                j++;
                widthEnd--;
                widthStart++;
                heightStart++;
                heightEnd--;
            }
            return v;
        }
    };
    

    包含min函数的栈

    描述

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

    源码

    class Solution {
    public:
        stack<int> s;
        stack<int> aux;
        
        void push(int value) {
            s.push(value);
            if(!aux.empty()){
                int t = aux.top();
                if(t>value){
                    aux.push(value);
                }else{
                    aux.push(t);
                }
            }else{
                aux.push(value);
            }
        }
        void pop() {
            s.pop();
            aux.pop();
        }
        int top() {
            return aux.top();
        }
        int min() {
            return aux.top();
        }
    };
    

    栈的压入、弹出序列

    描述

    输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列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) {
            if(pushV.empty() || popV.empty()){
                return false;
            }
            
            int start = 0;
            int cnt =0;
            stack<int> s;
            while(cnt<popV.size()){
                int p = popV[cnt];
                
                if(!s.empty() && s.top()==p){
                    s.pop();
                }else{
                    for(;start<pushV.size();start++){
                        s.push(pushV[start]);
                        if(pushV[start]==p){
                            start++;
                            break;
                        }
                    }
                    if(s.top()==p){
                        s.pop();
                    }else{
                        return false;
                    }
                }
                
                cnt++;
            }
            return true;
        }
    };
    

    从上往下打印二叉树

    描述

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

    源码

    /*
    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> vec;
            if(root==nullptr){
                return vec;
            }
            deque<TreeNode*> q;
            q.push_back(root);
            while(!q.empty()){
                auto tmp = q.front();
                q.pop_front();
                vec.push_back(tmp->val);
                if(tmp->left){
                    q.push_back(tmp->left);
                }
                if(tmp->right){
                    q.push_back(tmp->right);
                }
            }
            return vec;
        }
    };
    

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

    描述

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

    源码

    class Solution {
    public:
        bool check(const vector<int>&seq,int start,int end){
            if(start>=end){
                return true;
            }
            int root = seq[end-1];
            int right = start;
            for(;right<end;right++){
                if(seq[right]>root){
                    break;
                }
            }
            for(int t=right;t<end;t++){
                if(seq[t]<root){
                    return false;
                }
            }
            
            return check(seq,start,right-1)&&check(seq,right,end-1);
        }
        
        
        bool VerifySquenceOfBST(vector<int> sequence) {
            if(sequence.size()==0){
                return false;
            }
            if(sequence.size()==1){
                return true;
            }
            
            return check(sequence,0,sequence.size());
        }
    };
    

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

    描述

    输入一颗二叉树的跟节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的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>> paths;
        vector<int> temp;
        
        void dfs(TreeNode* root, int target){
            if(target-root->val==0 && root->left==nullptr && root->right==nullptr){
                temp.push_back(root->val);
                paths.push_back(temp);
                temp.pop_back();
                return;
            }
            
            if(root->left){
                temp.push_back(root->val);
                dfs(root->left,target- root->val);
                temp.pop_back();
            }
            if(root->right){
                temp.push_back(root->val);
                dfs(root->right,target- root->val);
                temp.pop_back();
            }
        }
        
        vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
            if(root==nullptr){
                return paths;
            }
            dfs(root,expectNumber);
            return paths;
        }
    };
    

    复杂链表的复制

    描述

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

    源码

    /*
    struct RandomListNode {
        int label;
        struct RandomListNode *next, *random;
        RandomListNode(int x) :
                label(x), next(NULL), random(NULL) {
        }
    };
    */
    class Solution {
    public:
        RandomListNode* seqClone(RandomListNode* pHead){
            RandomListNode* head = new RandomListNode(pHead->label);
            head->random = pHead->random;
            pHead=pHead->next;
            RandomListNode* copied =head;
            while(pHead){
                RandomListNode*temp = new RandomListNode(pHead->label);
                temp->random = pHead->random;
                head->next = temp;
                head = head->next;
                pHead=pHead->next;
            }
            return copied;
        }
        int getPos(RandomListNode * head,RandomListNode* target){
            int i=0;
            do{
                if(target==head){
                    return i;
                }
                head=head->next;
                i++;
            }while(head);
            return i;
        }
        RandomListNode* getNode(RandomListNode* head,int i){
            int s=0;
            while(s<i){
                head=head->next;
                s++;
            }
            return head;
        }
        
        RandomListNode* Clone(RandomListNode* pHead){
            if(pHead==nullptr){
                return nullptr;
            }
            RandomListNode* copied = seqClone(pHead);
            RandomListNode* t = copied;
            while(t){
                int pos = getPos(pHead,t->random);
                t->random = getNode(copied,pos);
                t=t->next;
            }
    
            return copied;
        }
    };
    

    二叉搜索树与双向链表

    描述

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

    源码

    /*
    struct TreeNode {
        int val;
        struct TreeNode *left;
        struct TreeNode *right;
        TreeNode(int x) :
                val(x), left(NULL), right(NULL) {
        }
    };*/
    class Solution {
    public:    
        void listify(TreeNode* cur, TreeNode*& pre){
            if(cur==nullptr){
                return;
            }
            listify(cur->left,pre);
            cur->left = pre;
            if(pre){
                pre->right = cur;
            }
            pre = cur;
            listify(cur->right,pre);
        }
        TreeNode* Convert(TreeNode* pRootOfTree){
            TreeNode* r = pRootOfTree;
            if(r!=nullptr){
                TreeNode* pre = nullptr;
                listify(r,pre);
                while(r->left){
                    r = r->left;
                }
                return r;
            }
            return r;
        }
    };
    

    字符串的排列

    描述

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

    源码

    class Solution {
    public:
        set<string> all;
        
        void dfs(string str,string a,vector<char> chars){
            if(a.length()==str.length()){
                all.insert(a);
                return;
            }
            for(int i=0;i<chars.size();i++){
                if(chars[i]!=''){
                    char c = chars[i];
                    chars[i]='';
                    dfs(str,a+c,chars);
                    chars[i] = c;
                }
            }
        }
        
        vector<string> Permutation(string str) {
            if(str.length()==0){
                return vector<string>();
            }
            vector<char> c;
            for(char val:str){
                c.push_back(val);
            }
            dfs(str,"",c);
            vector<string> res;
            for(const string &s:all){
                res.push_back(s);
            }
            return res;
        }
    };
    

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

    描述

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

    源码

    class Solution {
    public:  
        int partition(vector<int> & arr, int left, int right){
            int i = left;
            int j = right;
            int pivot = arr[left];
            while(i<j){
                while(i<j && arr[j]>pivot) j--;
                if(i<j) arr[i++] = arr[j];
                while(i<j && arr[i]<pivot) i++;
                if(i<j) arr[j--] = arr[i];
            }
            arr[i] = pivot;
            return i;
        }
        
        int MoreThanHalfNum_Solution(vector<int> numbers) {
            int start=0,end = numbers.size()-1;
            int index = partition(numbers,0,end);
            while(index!=numbers.size()/2){
                if(index>numbers.size()/2){
                    end = index -1;
                    index = partition(numbers,start,end);
                }else{
                    start = index+1;
                    index = partition(numbers,start,end);
                }
            }
            int cnt = 0;
            for(int i=0;i<numbers.size();i++){
                if(numbers[i]==numbers[index]){
                    cnt++;
                }
            }
            return cnt>index?numbers[index]:0;
        }
    };
    

    最小的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) {
            if(input.size()==0||k<=0 || input.size()<k){
                return vector<int>();
            }
            vector<int> v;
            make_heap(input.begin(),input.end(),greater<int>());
            for(int i=0;i<k;i++){
                pop_heap(input.begin(),input.end(),greater<int>());
                v.push_back(input[input.size()-1]);
                input.pop_back();
            }
            return v;
        }
    };
    

    连续子数组的最大和

    描述

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

    class Solution {
    public:
        int dp[1000]={0};
        
        int FindGreatestSumOfSubArray(vector<int> array) {
            if(array.size()==0){
                return 0;
            }
            for(int i=0;i<array.size();i++){
                dp[i+1] = dp[i]>0?array[i]+dp[i]:array[i];
            }
            int m=INT_MIN;
            for(int i=1;i<=array.size();i++){
                if(dp[i]>m){
                    m=dp[i];
                }
            }
            return m;
        }
    };
    

    把数组排成最小的数

    描述

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

    class Solution {
    public:
        static int cmp(int a,int b){
            string str1,str2;
            str1+=to_string(a);
            str1+=to_string(b);
            str2+=to_string(b);
            str2+=to_string(a);
            return str1<str2;
        }
        string PrintMinNumber(vector<int> numbers) {
            sort(numbers.begin(),numbers.end(),cmp);
            string result;
            for(int i:numbers){
                result+=to_string(i);
            }
            return result;
        }
    };
    

    丑数

    描述

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

    源码

    class Solution {
    public:
        int findMin(int a,int b,int c){
            int t = (a>b?b:a);
            return (t>c?c:t);
        }
        
        int GetUglyNumber_Solution(int index){
            if(index<=1){
                return index;
            }
            int p2=0,p3=0,p5=0;
            vector<int> v;
            v.push_back(1);
            while(v.size()<index){
                int min = findMin(v[p2]*2,v[p3]*3,v[p5]*5);
                if(v[p2]*2==min)p2++;
                if(v[p3]*3==min)p3++;
                if(v[p5]*5==min)p5++;
                v.push_back(min);
            }
            return v[v.size()-1];
        }
    };
    

    第一个只出现一次的字符

    描述

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

    源码

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

    数组中的逆序对

    描述

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

    源码

    class Solution {
    public:
        int cnt;
        
        void divide(vector<int> &arr,int start, int end){
            if(start>=end){
                return;
            }    
            int mid = (start+end)>>1;
            divide(arr,start,mid);
            divide(arr,mid+1,end);
            merge(arr,start,mid,end);
        }
        
        void merge(vector<int> &arr,int start, int mid, int end){
            int* aux = new int[end-start+1];
            
            int i=start,j=mid+1,k=0;
            while(i<=mid && j<= end){
                if(arr[i]<=arr[j]){
                    aux[k++]=arr[i++];
                }else{
                    aux[k++]=arr[j++];
                    cnt += (mid-i+1);
                    cnt %= 1000000007;
                }
            }
            
            while(i<=mid){
                aux[k++]=arr[i++];
            }
            while(j<=end){
                aux[k++]=arr[j++];
            }
            for(int i=0;i<end-start+1;i++){
                arr[start+i]=aux[i];
            }
            delete[]aux;
        }
        
        int InversePairs(vector<int> data) {
            cnt=0;
            if(data.size()==0){
                return cnt;
            }
            divide(data,0,data.size()-1);
            return cnt;
        }
    };
    

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

    描述

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

    源码

    /*
    struct ListNode {
        int val;
        struct ListNode *next;
        ListNode(int x) :
                val(x), next(NULL) {
        }
    };*/
    class Solution {
    public:
        ListNode* FindFirstCommonNode( ListNode* pHead1, ListNode* pHead2) {
            if(pHead1==nullptr||pHead2==nullptr){
                return nullptr;
            }
            stack<ListNode*> a,b;
            ListNode* t1=pHead1,*t2=pHead2;
            while(t1){
                a.push(t1);
                t1=t1->next;
            }
            while(t2){
                b.push(t2);
                t2=t2->next;
            }
            while(!a.empty()&&!b.empty()){
                t1=a.top();
                t2=b.top();
                if(t1!=t2){
                    return t1->next;
                }
                a.pop();
                b.pop();
            }
            if(a.empty()&&!b.empty()){
                return b.top()->next;
            }else if(b.empty()&&!a.empty()){
                return a.top()->next;
            }else{
                return pHead1;
            }
        }
    };
    

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

    描述

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

    源码

    class Solution {
    public:
        int GetNumberOfK(vector<int> data ,int k) {
            auto pos = find(data.begin(),data.end(),k);
            if(pos==data.end()){
                return 0;
            }
            int cnt=0;
            while(true){
                if(*pos==k){
                    cnt++;
                }else{
                    break;
                }
                pos++;
            }
            return cnt;
        }
    };
    

    二叉树的深度

    描述

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

    源码

    /*
    struct TreeNode {
        int val;
        struct TreeNode *left;
        struct TreeNode *right;
        TreeNode(int x) :
                val(x), left(NULL), right(NULL) {
        }
    };*/
    class Solution {
    public:
        int max = 0;
        
        void dfs(TreeNode* node,int depth){
            if(!node){
                if(depth>max){
                    max = depth;
                }        
                return;
            }
            dfs(node->left,depth+1);
            dfs(node->right,depth+1);
        }
        
        int TreeDepth(TreeNode* pRoot){
            if(pRoot==nullptr){
                return 0;
            }
            dfs(pRoot,0);
            return max;
        
        }
    };
    

    平衡二叉树

    描述

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

    源码

    class Solution {
    public:
        bool isBalanced=true;
        
        int dfs(TreeNode* node){
            if(!node){
                return 0;
            }
            int a = dfs(node->left);
            int b = dfs(node->right);
            if(abs(a-b)>1){
                isBalanced=false;
            }
            return a>b?a+1:b+1;
        }
        bool IsBalanced_Solution(TreeNode* pRoot) {
            if(pRoot==nullptr){
                return true;
            }
            dfs(pRoot);
            return isBalanced;
        }
    };
    

    数组中只出现一次的数字

    描述

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

    源码

    class Solution {
    public:
        void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
            map<int,int> m;
            for(int i:data){
                m[i]++;
            }
            
            bool first = true;
            for(auto v:m){
                if(v.second==1){
                    if(first){
                        *num1 = v.first;
                        first=false;
                    }else{
                        *num2=v.first;
                    }
                }
            }
        }
    };
    

    和为S的连续正数序列

    描述

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

    源码

    class Solution {
    public:
        int calcSum(int start, int end){
            return (start+end)*(end-start+1)/2;
        }
        vector<vector<int> > FindContinuousSequence(int sum) {
            vector<vector<int>> res;
            int start = 1;
            int end = 2;
            while(start<end){
                if(calcSum(start,end)<sum){
                    end++;
                }else if(calcSum(start,end)>sum){
                    start++;
                }else{
                    vector<int> v;
                    for(int i=start;i<=end;i++){
                        v.push_back(i);
                    }
                    res.push_back(v);
                    start++;    // or end++;
                }
            }
            return res;
        }
    };
    

    和为S的两个数字

    描述

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

    源码

    class Solution {
    public:
        vector<int> FindNumbersWithSum(vector<int> array,int sum) {
            int i=0;
            for(;i<array.size();i++){
                if(array[i]>=sum){
                    break;
                }
            }
            vector<int> v;
            int start  = 0;
            int end = (i==array.size())?i-1:i;
            while(start<end){
                if(array[start]+array[end]==sum){
                    v.push_back(array[start]);
                    v.push_back(array[end]);
                    return v;
                }else if(array[start]+array[end]>sum){
                    end--;
                }else if(array[start]+array[end]<sum){
                    start++;
                }
            }
            return v;
        }
    };
    

    左旋转字符串

    描述

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

    源码

    class Solution {
    public:
        string LeftRotateString(string str, int n) {
            string s;
            for(int i=n;i<str.length();i++){
                s+=str[i];
            }
            for(int i=0;i<n;i++){
                s+=str[i];
            }
            return s;
        }
    };
    

    翻转单词顺序列

    描述

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

    源码

    class Solution {
    public:
        void bitwise_reverse(string &str){
            int cnt=0;
            int last = 0;
            while(cnt<=str.length()){
                if(cnt==str.length() || str[cnt]==' '){
                    int left=last,right=cnt-1;
                    while(left<right){
                        char tmp = str[left];
                        str[left] = str[right];
                        str[right] = tmp;
                        left++;
                        right--;
                    }
                    last = cnt+1;
                }
                cnt++;
            }
        }
        
        string ReverseSentence(string str) {
            bitwise_reverse(str);
            for(int i=0,j=str.length()-1;i<j;i++,j--){
                char tmp = str[i];
                str[i]=str[j];
                str[j]=tmp;
            }
            return str;
        }
    };
    

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

    描述

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

    源码

    class Solution {
    public:
        // https://blog.csdn.net/byn12345/article/details/79487253
        int LastRemaining_Solution(int n, int m){
            if(n==0){
                return -1;
            }
            
            int cur=0;
            for(int i=2;i<=n;i++){
                cur = (cur+m)%i;
            }
            return cur;
        }
    };
    

    求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) {
            return (int)(n+std::pow(n,2))>>1;
        }
    };
    

    不用加减乘除做加法

    描述

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

    源码

    class Solution {
    public:
        int Add(int num1, int num2){
             return std::plus<>{}(num1,num2);
        }
    };
    

    把字符串转换成整数

    描述

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

    源码

    class Solution {
    public:
        int StrToInt(string str) {
            if(str.length()==0){
                return 0;
            }
    
            int start = 0;
            if(str[0]=='+'|| str[0]=='-'){
                start=1;
            }
            int res = 0;
            for(int i=start;i<str.length();i++){
                if(str[i]<'0'||str[i]>'9'){
                    return false;
                }else{
                    res = res*10 + (str[i]-'0'); 
                }
            }
            return str[0]=='-'?-res:res;
        }
    };
    

    数组中重复的数字

    描述

    在一个长度为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) {
             if(numbers==nullptr||length<=0){
                return false;
             }
            for(int i=0;i<length;i++){
                if(numbers[i]<0|| numbers[i]>length-1){
                    return false;
                }
            }
        
            for(int i=0;i<length;i++){
                while(numbers[i]!=i){
                    if(numbers[i]!=numbers[numbers[i]]){
                        std::swap(numbers[i],numbers[numbers[i]]);
                    }else{
                        *duplication=numbers[i];
                        return true;
                    }
                                
                }
            }
        return false;
        }
    };
    

    构建乘积数组

    描述

    给定一个数组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());
            if(A.size()==0){
                return b;
            }
            b[0]=1;
            for(int i=1;i<A.size();i++){
                b[i] = b[i-1]*A[i-1];
            }
            int t = 1;
            for(int i=A.size()-2;i>=0;i--){
                t = t*A[i+1];
                b[i] *= t;
            }
            return b;
        }
    };
    

    正则表达式匹配

    描述

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

    源码

    class Solution {
    public:
        bool matchImpl(char* str, char* pattern){
           if(*str!='' && *pattern==''){
               return false;    
           }
           if(*pattern=='' && *str==''){
               return true;
           }
          
            // 如果是重复匹配
           if(*(pattern+1)=='*'){
               if(*str==*pattern || *pattern=='.' && *str!=''){
                   return matchImpl(str+1,pattern+2)||
                       matchImpl(str+1,pattern)||
                       matchImpl(str,pattern+2);
               }else{
                   return matchImpl(str,pattern+2);
               }
           }
           // 如果是任意匹配
           if(*pattern=='.'&&*str!=''){
               return matchImpl(str+1,pattern+1);
           }
            // 如果是普通字符和数字
           if(*pattern==*str){
               return matchImpl(str+1,pattern+1);
           } else{
               return false; 
           }
        }
        
        bool match(char* str, char* pattern){
            if(str==nullptr||pattern==nullptr)
                return false;
            return matchImpl(str,pattern);
        }
    };
    

    表示数值的字符串

    描述

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

    源码

    class Solution {
    public:
        bool modeDecimal(char* string){
            while(*string){
                 if(*string=='e'||*string=='E'){
                    string++;
                    return modeScientific(string);
                }
                
                if(*string<'0'||*string>'9' ){
                    return false;
                }
                string++;
            }   
            return true;
        }
        
        bool modeScientific(char *string){
            // e后部分
            if(*string=='+'||*string=='-'){
                string++;
            }
            // e后至少一个数
            if(*string==''){
                return false;
            }
            while(*string){
                if(*string<'0'||*string>'9' ){
                    return false;
                }
                string++;
            }
            return true;
        }
        bool isNumeric(char* string){
            if(string==nullptr){
                return false;
            }
            bool isDigit = true;
            if(*string=='+'||*string=='-'){
                string++;
            }
            // 整数部分
            while(*string){
                if(*string=='.'){
                    string++;
                    return modeDecimal(string);  
                }
                
                if(*string=='e'||*string=='E'){
                    string++;
                    return modeScientific(string);
                }
                
                if(*string<'0'||*string>'9'){
                    return false;
                }
                string++;
            }
            return true;
        }
    
    };
    

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

    描述

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

    源码

    class Solution
    {
    public:
        string sub;
        map<char,int> m;
        
      //Insert one char from stringstream
        void Insert(char ch){
            m[ch]++;     
            sub+=ch;
        }
      //return the first appearence once char in current stringstream
        char FirstAppearingOnce(){
            for(int i=0;i<sub.length();i++){
                if(m[sub[i]]==1){
                    return sub[i];
                }
            }
            return '#';
        }
    
    };
    

    链表中环的入口结点

    描述

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

    源码

    /*
    struct ListNode {
        int val;
        struct ListNode *next;
        ListNode(int x) :
            val(x), next(NULL) {
        }
    };
    */
    class Solution {
    public:
        ListNode* jointPoint(ListNode* pHead){ 
            ListNode* slow = pHead->next;
            ListNode* fast = slow->next;
            
            while(fast!=nullptr && slow!=nullptr){
                if(fast==slow){
                    return fast;
                }
                slow = slow->next;
                fast  =fast ->next;
                if(fast!=nullptr){
                    fast = fast->next;
                }else{
                    return nullptr;
                }
            }
            return nullptr;
        }
        ListNode* EntryNodeOfLoop(ListNode* pHead){
            // 两个节点无法组成换
            if(pHead==nullptr || pHead->next->next==nullptr){
                return nullptr;
            }
            // 确认有环
            ListNode* join = jointPoint(pHead);
            if(!join){
                return nullptr;
            }
            // 找到环的节点数
            int cnt = 1;
            ListNode* circleStart = join->next;
            while(circleStart!=join){
                circleStart=circleStart->next;
                cnt++;
            }
            
            // 找到入口
            ListNode* slow = pHead;
            ListNode* fast = pHead;
            for(int i=0;i<cnt;i++){
                fast=fast->next;
            }
            while(slow!=fast){
                slow=slow->next;
                fast=fast->next;
            }
            return slow;
        }
    };
    

    删除链表中重复的结点

    描述

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

    源码

    /*
    struct ListNode {
        int val;
        struct ListNode *next;
        ListNode(int x) :
            val(x), next(NULL) {
        }
    };
    */
    class Solution {
    public:
        bool hasDuplicatedSeq(ListNode* pHead){
            if(pHead->next && pHead->next->next &&
               pHead->next->val == pHead->next->next->val){
                return true;
            }
            return false;
        }
        
        ListNode* removeDuplicatedSeq(ListNode* pHead){
            ListNode* current = pHead;
            ListNode* duplicatedTail = nullptr;
            // 删除重复序列
            while(true){
                if(current->next && 
                   current->val==current->next->val){
                    ListNode* tmp = current;
                    current = current->next;
                    delete tmp;
                    continue;
                }
                break;
            }
            duplicatedTail = current->next;
            delete current;
            
            return duplicatedTail;
        }
        
        ListNode* deleteDuplication(ListNode* pHead){
            if(pHead==nullptr){
                return nullptr;
            }
    
            ListNode* newHead = new ListNode(-1);
            newHead->next = pHead;
            ListNode* reservedNewHead = newHead;
            
            while(newHead){
                // 如果发现有重复的元素序列
                if(hasDuplicatedSeq(newHead)){
                    // 删除重复序列
                    ListNode* duplicatedTail = removeDuplicatedSeq(newHead->next);
                    
                   // 调整链表的链
                   newHead->next = duplicatedTail;
                    // 注意这里用conitnue而不是继续是因为有可能由于两个连续
                    // 的重复序列: 1->2->3->3->4->4->5
                   continue;
                }
                newHead = newHead->next;
            }
            return reservedNewHead->next;
        }
    };
    

    二叉树的下一个结点

    描述

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

    源码

    /*
    public class TreeLinkNode {
        int val;
        TreeLinkNode left = null;
        TreeLinkNode right = null;
        TreeLinkNode next = null;
    
        TreeLinkNode(int val) {
            this.val = val;
        }
    }
    */
    public class Solution {
        public TreeLinkNode GetNext(TreeLinkNode pNode)
        {
            if(pNode==null){
                return null;
            }
    
            if(pNode.right!=null){
                TreeLinkNode temp = pNode.right;
                while(temp.left!=null && temp.right!=null){
                    temp = temp.left;
                }
                return temp;
            }else if(pNode.right ==null){
                if(pNode.next!=null){
                     // 如果父节点不为空,且当前节点是父节点的左节点
                    if(pNode.next.left==pNode){
                        return pNode.next;
                    }else{
                    // 如果父节点不为空,且当前节点是父节点的右节点
                        TreeLinkNode t = pNode;
                        while(t.next!=null && t.next.left!=t){
                            t=t.next;
                        }
                        return t.next;
                    }
                }else{
                    return null;
                }
            }else{
                return null;
            }
        }
    }
    

    对称的二叉树

    描述

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

    源码

    /*
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;
    
        public TreeNode(int val) {
            this.val = val;
    
        }
    
    }
    */
    public class Solution {
        boolean check(TreeNode a,TreeNode b){
            if(a==null||b==null)
                return a==b?true:false;
            
            if(a.val==b.val){
                return check(a.left,b.right)&&check(a.right,b.left);
            }else{
                return false;
            }
            
        }
        
        boolean isSymmetrical(TreeNode pRoot){
            if(pRoot==null){
                return true;
            }
            return check(pRoot.left,pRoot.right);
        }
    }
    

    按之字形顺序打印二叉树

    描述

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

    源码

    /*
    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> > Print(TreeNode* pRoot) {
            vector<vector<int> > res;
            if(pRoot==nullptr){
                return res;
            }
            
            stack<TreeNode*> sk1,sk2;
            sk1.push(pRoot);
            while(!sk1.empty() || !sk2.empty()){
                 vector<int> v;
                
                if(!sk1.empty()){  
                    while(!sk1.empty()){
                        TreeNode *t = sk1.top();
                        v.push_back(t->val);
                        sk1.pop();
                        if(t->left)sk2.push(t->left);
                        if(t->right)sk2.push(t->right);
                    }
                }else{
                    while(!sk2.empty()){
                        TreeNode*t = sk2.top();
                        v.push_back(t->val);
                        sk2.pop();
                        if(t->right)sk1.push(t->right);
                        if(t->left)sk1.push(t->left);
                    }
                }
                
                res.push_back(v);
            }
            return res;
        }
        
    };
    

    把二叉树打印成多行

    描述

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

    源码

    /*
    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> > Print(TreeNode* pRoot) {
                vector<vector<int>> vec;
                if(pRoot==nullptr){
                    return vec;
                }
                deque<TreeNode*> q;
                q.push_back(pRoot);
                q.push_back(nullptr);
                while(!q.empty() && q.front()!=nullptr){
                    auto r = q.front();
                    q.pop_front();
                    vector<int> v;
                    while(r!=nullptr){
                        v.push_back(r->val);
                        if(r->left){
                            q.push_back(r->left);
                        }
                        if(r->right){
                            q.push_back(r->right);
                        }
                        r=q.front();
                        q.pop_front();
                    }
                    vec.push_back(v);
                    q.push_back(nullptr);;  
                }
                return vec;
            }
        
    };
    

    二叉搜索树的第k个结点

    描述

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

    源码

    /*
    struct TreeNode {
        int val;
        struct TreeNode *left;
        struct TreeNode *right;
        TreeNode(int x) :
                val(x), left(NULL), right(NULL) {
        }
    };
    */
    class Solution {
    public:
        int cnt = 0;
        TreeNode* result=nullptr;
        
        void traverse(TreeNode* t,int target){
            if(t){
                traverse(t->left,target);
                cnt++;
                if(cnt==target){
                    result = t;
                    return;
                }
                traverse(t->right,target);
            }    
        }
        
        TreeNode* KthNode(TreeNode* pRoot, int k){
            if(k==0||pRoot==nullptr){
                return nullptr;
            }
            traverse(pRoot,k);
            return result;
        }
    
        
    };
    

    数据流中的中位数

    描述

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

    源码

    class Solution {
    public:
        priority_queue<int, vector<int>, less<int> > max;
        priority_queue<int, vector<int>, greater<int> > min;
        int cnt=0;
        
        void Insert(int num){
            if(cnt%2){
                max.push(num);
                min.push(max.top());
                max.pop();
            }else{
                min.push(num);
                max.push(min.top());
                min.pop();
            }
            cnt++;
        }
    
        double GetMedian(){ 
            return cnt%2!=0?max.top():(max.top()+min.top())/2.0;
        }
    
    };
    

    滑动窗口的最大值

    描述

    给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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){
            vector<int> vec;
            if(num.size()<size || size==0){
                return vec;
            }
            deque<int> q;
            for(int i=0;i<num.size();i++){
                while(!q.empty() && num[q.back()]<=num[i]){
                    q.pop_back();
                }
                while(!q.empty() && i-q.front()+1>size){
                    q.pop_front();
                }
                q.push_back(i);
                if(i+1>=size){
                    vec.push_back(num[q.front()]);
                }
            }
            return vec;
        }
    };
    

    矩阵中的路径

    描述

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

    源码

    class Solution {
    public:
        bool correctPath(char* matrix, int rows, int cols, char* str,
                         int i, int k,int *visited, int step){
            if(i<0 || k<0 || i>=rows || k>= cols){
                return false;
            }
            if(visited[i*cols+k] ||
               str[step]!=matrix[i*cols+k]){
                return false;
            }
            
            if(step == strlen(str)-1){
                return true;
            }
            
            visited[i*cols+k] = true;
            if(correctPath(matrix,rows,cols,str,i,k+1,visited,step+1)||
              correctPath(matrix,rows,cols,str,i,k-1,visited,step+1)||
              correctPath(matrix,rows,cols,str,i-1,k,visited,step+1)||
              correctPath(matrix,rows,cols,str,i+1,k,visited,step+1)){
                return true;
            }
            visited[i*cols+k]=false;
              
            return false;
        }
         
        bool hasPath(char* matrix, int rows, int cols, char* str){
            int * visited = new int[rows*cols];
            memset(visited,0,sizeof(int)*rows*cols);
             
            for(int i=0;i<rows;i++){
                for(int k=0;k<cols;k++){
                    if(correctPath(matrix,rows,cols,str,i,k,visited,0)){
                        delete visited;
                        return true;
                    }
                }
            }
             
            delete visited;
            return false;
        }
     
     
    };
    

    机器人的运动范围

    描述

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

    源码

    int visited[100][100];
    
    class Solution {
    public:
        int sumDigit(int num){
            int res = 0;
            while(num){
                res += (num%10);
                num /= 10;
            }
            return res;
        }
        
        int dfs(int rows, int cols, int i,int k,int threshold){
            if(i<0 || k <0 || i>=rows || k>=cols || visited[i][k]){
                return 0;
            }
            if(sumDigit(i)+sumDigit(k)>threshold){
                return 0;
            }
            
            visited[i][k]=true;
            int a = 1 + dfs(rows,cols,i,k+1,threshold)
                      + dfs(rows,cols,i,k-1,threshold)
                      + dfs(rows,cols,i-1,k,threshold)
                      + dfs(rows,cols,i+1,k,threshold);
            return a;
        }
        
        int movingCount(int threshold, int rows, int cols){
            int max=0;
            memset(visited,0,10000*sizeof(int));
    
            return dfs(rows,cols,0,0,threshold);
        }
    };
    
  • 相关阅读:
    【HDU
    写个shell脚本依次运行每个程序半小时
    Windows10 + Visual Studio 2017环境为C++工程安装使用ZMQ
    【UVALive
    【Gym
    【最短路算法】Dijkstra+heap和SPFA的区别
    【Gym 100812C】Story of Princess (走完图所有边)
    【C++】VS2015/VS2017连接Mysql数据库教程
    博客园设置Google-code-prettify渲染代码高亮
    【QML与C++混合编程】用QVariantList传递数组类型成员
  • 原文地址:https://www.cnblogs.com/ysherlock/p/10596557.html
Copyright © 2011-2022 走看看