劍指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]!='\0'){
                char c = chars[i];
                chars[i]='\0';
                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!='\0' && *pattern=='\0'){
           return false;    
       }
       if(*pattern=='\0' && *str=='\0'){
           return true;
       }
      
        // 如果是重複匹配
       if(*(pattern+1)=='*'){
           if(*str==*pattern || *pattern=='.' && *str!='\0'){
               return matchImpl(str+1,pattern+2)||
                   matchImpl(str+1,pattern)||
                   matchImpl(str,pattern+2);
           }else{
               return matchImpl(str,pattern+2);
           }
       }
       // 如果是任意匹配
       if(*pattern=='.'&&*str!='\0'){
           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=='\0'){
            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);
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章