1. 程式人生 > >牛客劍指offer刷題記錄(一)

牛客劍指offer刷題記錄(一)

1.二維陣列查詢

本題的關鍵就在於二維陣列具有一定的特性:
從左往右,從上往下呈遞增序列。

如果二次遍歷,就失去了這個題目的意義因為複雜度是O(n2)

對於這個矩陣來說,左上角的值a(0,0)一定為最小值,右下角的值a(m,n)一定是最大值,當與target比較完了之後,我們不知道該往哪邊走。因此,可以選取左下角a(m,0)或者右上角a(0,n)開始,這樣如果target比較大,一定往下(上)走,target比較小,一定往左(右)走。


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

2.替換空格

這題主要是考察,對陣列擴容的時候可以先計算擴容後的大小,比如這題,先計算空格有多少個,然後加上原有字元的個數,就是擴容後的大小。最後插入的時候從後往前操作,可以保證演算法的原地的執行(in place)

此題的擴充套件就是,兩個排好序的數組合併成一個有序陣列,可以考慮先對其中一個數組進行擴容,之後再把另一個數組的值從後往前插入。

class Solution {
public:
    void replaceSpace(char *&str,int length) {
        if(NULL==str)
            return;
        char *p=str;
        int space=0;
        while(*p!='\0')
        {
            if(*p==' ')
                ++space;
            ++p;
        }
        char *copy= (char *)malloc((2*space+length+1)*sizeof(char));
        *(copy+2*space+length)='\0';
        int j=2*space+length-1;
        int i=length-1;
        while(i>=0)
        {
            if(*(str+i)==' ')
            {
                *(copy+j)='0';
                *(copy+j-1)='2';
                *(copy+j-2)='%';
                j-=3;
                --i;
            }
            else
            {
                *(copy+j)=*(str+i);
                --j;
                --i;
            }
        }
        char *tmp=copy;
        copy=str;
        str=tmp;
        cout<<str<<endl;
    }
};

3.從尾到頭列印連結串列

連結串列這個資料結構,如果指標域是單向的,那麼它的迭代也是單向的,也即不能向陣列那樣,隨機的訪問最後一個元素,再往前列印。

解決的方案有很多。最直觀的方法是,從前往後遍歷,然後將遍歷的value壓棧,這樣彈棧的時候就是原連結串列相反的順序。

遞迴是另一種形式,遞迴的呼叫函式使其以連結串列的下一個節點做當前節點,就達到了遍歷的效果,然後在遞迴返回之際列印相應值,就反序了。因為遞迴其實就是函式棧,所以思想跟上一個差不多

class Solution {
private:
    void help(ListNode * head,vector<int>&v)
    {
        if(head!=NULL)
        {
            if(head->next!=NULL)
            {
                help(head->next,v);
            }
            v.push_back(head->val);
        }
    }
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        if(NULL==head)
            return vector<int>();
        vector<int>tmp;
        help(head,tmp);
        return tmp;

    }
};

4.重建二叉樹

此題的擴充套件就是,假設我們現在要序列化一個二叉樹,那麼我們可以儲存其先序和中序的序列,資料到remote端以後,然後再rebuild一下。

先序遍歷序列找到根節點,中序遍歷序列將又通過根節點劃分兩個左右子樹。為了方便快捷的在中序遍歷的序列中找到根節點所在位置,可以用一個map記錄根節點值和索引的key-value對。

此外,在先序遍歷中,要找到子樹根的位置,還必須通過中序遍歷計算劃分之後,左子樹和右子樹的節點個數。因此,我用了4個引數來記錄:

preStart//子樹先序開始
preEnd//子樹先序結束
inStart//子樹中序開始
inEnd//子樹中序結束

遞迴的方式去構建二叉樹,每次都去更新這些數的值

class Solution {
private:
    TreeNode * help(vector<int>&pre,//pre seq
        vector<int>&vin,//in seq
        int preStart,   //pre start idx
        int preEnd,     //pre end idx
        int inStart,    //in start idx
        int inEnd,    //in end idx
        unordered_map<int, int>&index)// map find idx in vin
    {
        if (inStart > inEnd)//
        {
            return NULL;
        }
        //先拿到根節點的值
        int rootval = pre[preStart];//root val
        //建立根節點
        TreeNode * root = new TreeNode(rootval); //root node
        //找到中序遍歷中根節點的索引
        int idx = index[rootval];//root index in vin
        //split vin with idx
        //通過索引計算中序中對左右子數的劃分(計算節點的個數),以便在先序中找到子樹的根
        //遞迴左子樹
        root->left = help(pre, vin, preStart + 1, preStart + idx - inStart, inStart, idx - 1, index);
        //遞迴右子樹
        root->right = help(pre, vin, preStart + idx - inStart + 1, preEnd, idx + 1, inEnd, index);
        return root;
    }
public:
    TreeNode* reConstructBinaryTree(vector<int> pre, vector<int> vin)
    {
        unordered_map<int, int>index;
        //計算中序遍歷序列中 值和索引的Key-value對
        for (int i = 0; i < vin.size(); ++i)
        {
            index[vin[i]] = i;
        }
        return help(pre, vin, 0, pre.size() - 1, 0, vin.size() - 1, index);

    }
};

5.兩個棧實現佇列

棧是後進先出,first-in-last-out
佇列是先進先出,first-in-first-out

現在由兩個棧,將元素插入到第一個棧中,再逐個彈出壓入第二個棧中,這樣在棧1中先入棧的元素,到了棧2中就越靠近棧頂,然後從棧2中彈棧,就達到了FIFO的效果。

這裡,不是每次彈棧都要講棧1的序列全部壓入棧2,只有當棧2為空的時候才這樣做。

class Solution
{
    public:
        void push(int node)
        {
            stack1.push(node);
        }
        int pop() 
        {
            if(!stack1.empty()||!stack2.empty())
            {
                if(stack2.empty())
                {
                    while(!stack1.empty())
                    {
                        stack2.push(stack1.top());
                        stack1.pop();
                    }
                }
                int t=stack2.top();
                stack2.pop();
                return t;
            }
            return -1;
        }
    private:
        stack<int> stack1;
        stack<int> stack2;
};

相關推薦

offer記錄

1.二維陣列查詢 本題的關鍵就在於二維陣列具有一定的特性: 從左往右,從上往下呈遞增序列。 如果二次遍歷,就失去了這個題目的意義因為複雜度是O(n2) 對於這個矩陣來說,左上角的值a(0,0)一定為最小值,右下角的值a(m,n)一定是最大值,當與ta

offer記錄11——二進位制中1的個數

題目描述 輸入一個整數,輸出該數二進位制表示中1的個數。其中負數用補碼錶示。 將輸入的整數分成0,正,負三種情況分別討論。正數和0不必多說,當負數時,要將反碼的32位用0補全,補碼是取反加一,再求1的個數,所以可以不必求補碼,直接轉化成反碼加0,1和0的代數關係進行調

offer記錄14——連結串列中倒數第k個結點

題目描述 輸入一個連結串列,輸出該連結串列中倒數第k個結點。 想到利用雙指標標記頭部,移動第二個指標直到距離為k - 1,再同時移動兩個指標,當第二個指標指向尾部,第一個指標則指向倒數第k個結點。 解法一: public class Solution {

offer記錄17——樹的子結構

題目描述 輸入兩棵二叉樹A,B,判斷B是不是A的子結構。(ps:我們約定空樹不是任意一個樹的子結構) 解法一:遞迴 public class Solution { public boolean HasSubtree(TreeNode root1, TreeN

offer記錄20——包含min函式的棧

題目描述 定義棧的資料結構,請在該型別中實現一個能夠得到棧中所含最小元素的min函式(時間複雜度應為O(1))。 解法: import java.util.Stack; import java.util.Iterator; public class Solutio

offer記錄26——二叉搜尋樹與雙向連結串列

題目描述 輸入一棵二叉搜尋樹,將該二叉搜尋樹轉換成一個排序的雙向連結串列。要求不能建立任何新的結點,只能調整樹中結點指標的指向。 public class Solution { public TreeNode Convert(TreeNode root) {

offer記錄25——複雜連結串列的複製

題目描述: 輸入一個複雜連結串列(每個節點中有節點值,以及兩個指標,一個指向下一個節點,另一個特殊指標指向任意一個節點),返回結果為複製後複雜連結串列的head   因為是一個複雜連結串列,每個節點有一個random屬性,導致無法採用簡單的一個一個節點進行復制的方法。 故而

offer記錄

連續子陣列的最大值 要求:例如:{6,-3,-2,7,-15,1,2,2},連續子向量的最大和為8(從第0個開始,到第3個為止)。給一個數組,返回它的最大連續子序列的和 class Solution { public: int FindGre

Offer 筆記20/66——JAVA

文章目錄 11.二進位制中1的個數 12.數值的整數次方 13.調整陣列順序使奇數位於偶數前面 14.連結串列中倒數第k個節點 15.反轉連結串列 16.合併兩個排序的連結串列 17.樹的

Offer筆記java實現_26.樹的子結構

題目描述:   輸入兩棵二叉樹A,B,判斷B是不是A的子結構。(ps:我們約定空樹不是任意一個樹的子結構)。 其實思路很簡單:我們的演算法就通過比較即可,因為是樹的遍歷比較所以第一時間想到了遞迴 先假設母樹為A,子樹為B (1)我們先去判斷節點的第一個點的值是

Offer筆記java實現_39.陣列中次數超過一半的數字

陣列中有一個數字出現的次數超過陣列長度的一半,請找出這個數字。 例如輸入陣列:{1,3,3,2,3,2,3,3,2}。由於2在陣列中出現了5次,超過陣列長度的一半,因此要輸出2。 三種解法: 第一種遍歷陣列,利用hashMap儲存每個數字出現的次數,時間複雜度O(n)

Offer 筆記30/66——JAVA

文章目錄 21.棧的壓入、彈出序列 22.從上往下列印二叉樹 23.二叉搜尋樹的後序遍歷序列 24.二叉樹中和為某一值的路徑 25.複雜連結串列的複製 26.二叉搜尋樹與雙向連結串列 27

Offer 筆記10/66——JAVA

如果你碰巧點進來想看解題思路的話,可以看下這位dalao寫的.挺詳細的~ https://blog.csdn.net/flushhip/article/details/79392028#commentBox 文章目錄 1.二維陣列中的查詢

offer心得面試篇

行為面試=》技術面試=》應聘者提問 1. 行為面試環節 專案經驗是重中之重,簡歷撰寫參考STAR模型:即Situation(簡短的專案背景),Task(完成的任務),Action(為完成任務做了哪些工作,怎麼做的),Result(自己的貢獻)

LeetCode記錄

LeetCode刷題記錄(一) 最近開始在LeetCode上面做題,想想應該做一個記錄,以便以後看到類似的問題及時查閱,同時也能夠將做題時的思路記錄下來,將這些思路整理歸納,形成一套我自己的解題思路。當然,演算法題只做一次是不夠的,需要多次的練習,可能每次的想法都不太一樣,在這裡我只

關於offer程式設計思路棧和佇列篇

相關題目來源 解題思路 1. 用兩個棧實現佇列 這道題阿里電話面試的時候問過,本來很簡單的,當時太不自信了qaq 首先一個stack是作為接受佇列的push輸入,另一個stack作為輸出pop,用效率比較高的方法是要pop的時候檢查一下stac

二維數組中的查找——offer

劍指offer 比較 direct [] data- ring 要求 als 步驟 題目描述: 在一個二維數組中(每個一維數組的長度相同),每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是

鏈表分割——offer

之前 排列 頭指針 print lse 遍歷 lis 例如 自建 題目描述: 編寫代碼,以給定值x為基準將鏈表分割成兩部分,所有小於x的結點排在大於或等於x的結點之前 給定一個鏈表的頭指針 ListNode pHead,請返回重新排列後的鏈表的頭指針。註意:分割以後保持原來

offer之反轉連結串列

題目描述 輸入一個連結串列,反轉連結串列後,輸出新連結串列的表頭。 # -*- coding:utf-8 -*- # class ListNode: #     def __init__(self, x): #        

offer之連結串列中倒數第k個結點

題目描述 輸入一個連結串列,輸出該連結串列中倒數第k個結點。 # -*- coding:utf-8 -*- # class ListNode: #     def __init__(self, x): #         s