10.11 牛客《劍指offer》 T1-12

10.11 牛客《劍指offer》 T1-12

T1 二維部分有序數組查找 ☆

在一個二維數組中(每個一維數組的長度相同),每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否含有該整數。

由於矩陣部分有序,向上數字遞減,向右數字遞增:

  1. 目標數字只會出現在行首小於該數的行中
  2. 遍歷行i ,若列j 對應的元素大於目標,那麼在前 i-1 行,目標只會出現在 j列及以後。

因此,可以從左下角開始查找。目標比左下角數字小時,上移;當要目標比左下角數字大時,右移。
搜索的路線是階梯狀,複雜度爲O(行數+列數)。

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

WA警告:

之前的錯誤代碼版本如下,由於判斷條件中的 && 寫成 , 造成段錯誤(數組越界訪問):

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        int nrows = array.size();
        int ncols = array[0].size();
        if( ncols == 0 || nrows == 0) return false;
        for(int i = nrows - 1, j = 0; i >= 0, j < ncols; i--){
            if( array[i][j] == target )
                return true;
            if( array[i][j] < target){
                i++;
                j++;
            }
        }
          
        return false;
    }
};

T2 字符串字符不等長替換 - 從後往前

請實現一個函數,將一個字符串中的每個空格替換成“%20”。例如,當字符串爲We Are Happy.則經過替換之後的字符串爲We%20Are%20Happy。

實現統計好空格數目從後往前寫。問題是 str 所指的空間會內存泄露吧?
注意補上 ‘\0’(應該不會有憨憨如我補了一個’\n’…

T3 返回鏈表的反序 vector

輸入一個鏈表,按鏈表從尾到頭的順序返回一個ArrayList。

遞歸或者對正序 vector reverse。

class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<int> rst;
        if(head == NULL)return rst;
        rst = printListFromTailToHead(head->next);
        rst.emplace_back(head->val);
        return rst;
    }
};

//----------------------vv---------------------------------
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        vector<int> rst;
         
        ListNode* pNode = head;
        while(pNode!=NULL){
            rst.emplace_back(pNode->val);
            pNode=pNode->next;
        }
         
        reverse(rst.begin(),rst.end());
        return rst;
    }
};

T4 重建二叉樹

輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。

遞歸建樹。注意遞歸出口,當有 0 或一個節點時直接返回。

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
        if(pre.size()==0)
            return NULL;
        if(pre.size()==1)
            return new TreeNode(pre[0]);
        TreeNode* root = new TreeNode(pre[0]);
        int lenl =0, lenr = 0,len = vin.size();
        while(lenl<len && vin[lenl]!= pre[0])
            lenl++;
        vector<int> npre,nvin;
        
        npre = vector<int>(pre.begin()+1,pre.begin()+1+lenl);
        nvin = vector<int>(vin.begin(),vin.begin()+lenl);
        root->left = reConstructBinaryTree(npre,nvin);
        
        npre = vector<int>(pre.begin()+1+lenl,pre.end());
        nvin = vector<int>(vin.begin()+lenl+1,vin.end());
        root->right = reConstructBinaryTree(npre,nvin);
        
        return root;
    }
};

T5 兩個棧模擬隊列

用兩個棧來實現一個隊列,完成隊列的Push和Pop操作。 隊列中的元素爲int類型。

棧1接收入隊列元素,棧2存儲出隊列元素,當棧2空時,把棧1元素倒到棧2中。

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

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

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

T6 旋轉數組中的最小元素 - 二分或暴力 ☆

把一個數組最開始的若干個元素搬到數組的末尾,我們稱之爲數組的旋轉。
輸入一個非遞減排序的數組的一個旋轉,輸出旋轉數組的最小元素。
例如數組{3,4,5,1,2}爲{1,2,3,4,5}的一個旋轉,該數組的最小值爲1。
NOTE:給出的所有元素都大於0,若數組大小爲0,請返回0。

由於旋轉後,數組前半段非減,後半段非減,所以從後往前遍歷,轉折點一定是最小元素。如果沒有轉折點,那麼所有元素都相等。(像這樣 ··``…·

但是這個轉折點可以試着二分。由於轉折處的右側是最小元素,所以選擇儘量讓區間右端點落在最小元素上。那麼:

  1. array[mid] > array[high]
    出現這種情況的array類似[3,4,5,6,0,1,2],此時最小數字一定在mid的右邊。
    low = mid + 1
  2. array[mid] == array[high]:
    出現這種情況的array類似 [1,0,1,1,1] 或者[1,1,1,0,1],此時最小數字不好判斷在mid左邊還是右邊,這時只好一步步縮小區間。
    high = high - 1
  3. array[mid] < array[high]:
    出現這種情況的array類似[2,2,3,4,5,6,6],此時最小數字一定就是array[mid]或者在mid的左邊。因爲右邊必然都是遞增的。
    high = mid

注意,考慮最後區間長爲2或爲3 的情況,上述的收斂方式都會使得 low 和 high 最終都指向最小元素。

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

T7 - 10 斐波那契數列 - 遞推遞歸 - 兩變量寫法

T7:大家都知道斐波那契數列,現在要求輸入一個整數n,請你輸出斐波那契數列的第n項(從0開始,第0項爲0)。 n<=39。

class Solution {
public:
    int Fibonacci(int n) {
        if(n==0) return 0;
        if(n==1) return 1;
        if(n==2) return 1;
        return Fibonacci(n-1)+Fibonacci(n-2);
    }
};

T8:一隻青蛙一次可以跳上1級臺階,也可以跳上2級。求該青蛙跳上一個n級的臺階總共有多少種跳法(先後次序不同算不同的結果)。

// 兩變量
class Solution {
public:
    int jumpFloor(int number) {
        if(number==0)return 1;
        if(number==1)return 1;
        if(number==2)return 2;
        int f=1,g=2;
        number-=2;
        while(number--){
            g=f+g;
            f=g-f;
        }
        return g;
    }
};

T9:一隻青蛙一次可以跳上1級臺階,也可以跳上2級……它也可以跳上n級。求該青蛙跳上一個n級的臺階總共有多少種跳法。

// dp
class Solution {
public:
    int jumpFloorII(const int number) {
        int** dp=new int*[number+10];
        for(int i=0;i<number+10;i++){
            dp[i]=new int[number+10];
        }
        
        memset(dp,0,sizeof dp);
        
        for(int i=1;i<=number;i++){
            dp[1][i]=1;
        }
        // dp[i][j] 用i步跳上臺階j
        for(int i=2;i<=number;i++){
            for(int j=i;j<=number;j++){
                for(int k=i-1;k<j;k++){
                    dp[i][j]+=dp[i-1][k];
                }
            }
        }
        
        int ans=0;
        for(int i=1;i<=number;i++){
            ans+=dp[i][number];  
        }
        return ans;// 返回的變量打錯,不可原諒,,
    }
};

T10:我們可以用2*1的小矩形橫着或者豎着去覆蓋更大的矩形。請問用n個2*1的小矩形無重疊地覆蓋一個2*n的大矩形,總共有多少種方法?

類似於前面幾題。

class Solution {
public:
    int rectCover(int number) {
        if(number==0)    return 0;
        if(number==1)    return 1;
        if(number==2)    return 2;
        int f=1,g=2;
        number-=2;
        while(number--){
            g=f+g;
            f=g-f;
        }
        return g;
    }
};

T11 二進制中 1 的個數

輸入一個整數,輸出該數二進制表示中1的個數。其中負數用補碼錶示。

注意對於負數,右移一位會補 1 而非補零。

// 1. 去掉符號位 1
class Solution {
public:
     int  NumberOf1(int n) {
         int cnt=0;
         if(n<0) {
             n &=0x7fffffff;
             cnt++;
         }
        
         while(n){
             cnt+=(n&1);
             n>>=1;
         }
         return cnt;
     }
};

// 2. 轉爲 unsigned int
class Solution {
public:
     int  NumberOf1(int n) {
         unsigned int nn=n;
         int cnt=0;

         while(nn){
             cnt+=(nn&1);
             nn>>=1;
         }
         return cnt;
     }
};

// 3. 每次 n&(n-1) 將從右邊起的第一個 1 變爲 0
public class Solution {
    public int NumberOf1(int n) {
        int count = 0;
        while(n!= 0){
            count++;
            n = n & (n - 1);
         }
        return count;
    }
} 

T12 數值的整數次方 - 縝密 - 基數可能爲負數

給定一個double類型的浮點數 base 和 int 類型的整數exponent。求base的exponent次方。 保證base和exponent不同時爲0

class Solution {
public:
    double Power(double base, int exponent) {
        double ans=1;
        bool neg= false;
        
        else if(exponent<0){
            neg=true;
            exponent=-exponent;
        }
        for( ; exponent; base*=base,exponent/=2){
            if(exponent&1){
                ans*=base;
            }
        }
        return neg?1/ans:ans;
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章