劍指offer第二版算法題解題思路總結

主要使用c++。

寫代碼時易錯點

-要考慮到特殊輸入并做相應處理,如空指針,空數組等。

題11 旋轉排序數組的最小數字

二分查找 。大體思路是 維護兩個指針,分別指向第一個和最后一個元素。然后找到數組中間的元素,如果這個值大于等于第一個指針指向的元素,那么該中間元素就位于數組中前面遞增的部分,這樣就把前面的指針指向該中間元素。如果這個中間值小于等于后面指針指向的元素,那么該中間值就位于數組中后面遞增的部分,這樣就把后面的指針指向中間元素。這樣不管時移動哪一個指針,查找范圍都會縮小為原來的一半,然后再對更新后的兩個指針做新一輪的查找。最終兩個指針會指向兩個相鄰的元素,而第二個指針正好是指向最小的元素,這就是循環結束的條件。

相關題目 旋轉數組中查找一個數 logN時間

題12 矩陣中的路徑

判斷矩陣中是否存在一條包含某字符串所有字符的路徑。
遞歸實現,回溯法。回溯法非常適合由多個步驟組成的問題,并且每個步驟都有多個選項,當我們在某一步選擇了其中的一個選項時,下一步又面臨新的多個選項。這樣重復選擇直到到達最終的狀態。用回溯法解決的問題的所有選項可以形象的用數狀結構來表示。
程序中都要用一個和原矩陣一樣大的bool矩陣visited來標記每個位置是否被訪問過。

題13 機器人的運動范圍

同題12。

相關題目 在0/1矩陣矩陣中的最大活動范圍。

遍歷每一個元素,每一個元素都可能作為起點。當然,這個時可以再優化的。

程序中都要用一個和原矩陣一樣大的bool矩陣visited來標記每個位置是否被訪問過。

題15 二進制中1的個數

題21 調整數組順序使奇數位于偶數前面

不要求穩定

維護兩個指針,初始化時分別指向第一個和最后一個數字,前面的指針只向后移動,后面的指針只向前移動。在兩個指針相遇之前,第一個指針總是位于第二個指針的前面。如果第一個指針指向的數字為偶數,第二個指針指向的數字為奇數,則交換這兩個數字。

要求穩定

用冒泡排序的思想,復雜度為O(n^2)。

void reOrderArray(vector<int> &array)
{
    for(int i = 0;i < array.size();i++)
    {
        for(int j = array.size()-1; j>i;j--)
        {
            if(array[j]%2==1&&array[j-1]%2==0)
                swap(array[j],array[j-1]);
        }
    }
}

題22 鏈表中倒數第k個節點

維護兩個指針,讓第一個指向第一節點,另一個指向第k個節點。然后兩個指針同步往后走,當后面的指針走到最后一個節點時,前面的指針正好就走到了倒數第k個節點。

相關問題 求鏈表的中間節點

維護兩個指針,同時從鏈表的頭節點出發,一個指針每次走一步,另一個指針一次走兩步,當走的快的指針走到鏈表的末尾時,走的慢的指針正好走到鏈表的中間。

題23 鏈表中環的入口節點

先確定鏈表中是否存在環,讓兩個指針都從頭節點出發,一個一次走一步,另一個走快些,比如一次走兩步,如果走的快的指針能追上走的慢的指針,那么鏈表中就有環,并且追上時的節點就是環中的節點。然后從這個節點出發一邊往后走一遍計數,再次回到這個節點時,就計數得到環中的節點個數了。環中節點個數設為k,這時鏈表中環的入口節點就相當于鏈表尾節點,同事也是倒數第k個節點。兩指針從頭節點出發,快指針先走k步,然后兩個同步走,當兩個指針相遇時,他們便是到了環的入口節點。

題24 反轉鏈表

思路一 用棧先進后出記住鏈表的順序,比較費內存

把所有節點依次放入一個棧里。最后的節點為要返回的節點,先保存著。然后從棧里每次取出節點,使其指向棧里的下一個節點。

思路二 連續的三個為一組,從前往后走

維護三個指針,分別指向當前要處理的節點、其前一個節點、其后面一個節點,逐步往后走。記住后面一個節點,以防當前節點反轉完后后面的節點找不到了。

題25 合并兩個排序的鏈表

比較合并兩個鏈表的頭節點,使用遞歸

class Solution {
public:
    ListNode* Merge(ListNode* pHead1, ListNode* pHead2)
    {
        if(pHead1 == nullptr)   return pHead2;
        else if(pHead2==nullptr) return pHead1;
        ListNode* pMergedHead = nullptr;
        if(pHead1->val<pHead2->val)
        {
            pMergedHead=pHead1;
            pMergedHead->next=Merge(pHead1->next,pHead2);
        }
        else
        {
            pMergedHead=pHead2;
            pMergedHead->next=Merge(pHead1,pHead2->next);
        }
        return pMergedHead;
    }
};

相關題目 合并兩個有序數組 參見這里的解法二和解法三

再熟悉下這個,再引申,合并n個有序數組呢

題32 從上倒下打印二叉樹

題33 二叉搜索樹的后序遍歷序列

題34 二叉樹中和為某一值的路徑

/*
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> > FindPath(TreeNode* root,int expectNumber) {
        vector<vector<int>> result;
        if(root == nullptr)
            return result;
        vector<int> path;
        int currentSum = 0;
        return FindPath( root,  expectNumber, path, currentSum,result);
    }
    vector<vector<int>> FindPath(TreeNode* root, int expectedNumber,vector<int>&path,int currentSum,vector<vector<int>>& result)
    {
        currentSum += root->val;
        path.push_back(root->val);
        
        bool isLeaf = root->left == nullptr && root->right==nullptr;
        if(isLeaf && currentSum==expectedNumber)
            result.push_back(path);
        if(root->left != nullptr)
            result = FindPath(root->left,expectedNumber,path,currentSum, result);
        if(root->right != nullptr)
            result = FindPath(root->right,expectedNumber,path,currentSum, result);
        path.pop_back();
        currentSum -=root->val;
        return result;
    }
};

題38 字符串的排列

題39 數組中出現次數超過一半的數字

題40 最小的k個數

題41 數據流中的中位數,這題太難了!

書上的解法中用到了平衡二叉搜索樹,太麻煩艱澀。牛客網上有用優先隊列來做的,優先隊列priority_queue本質也是一個堆。

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

題42 連續子數組的最大和

#include<bits/stdc++.h>
using namespace std;
int FindGreatestSumOfSubArray(vector<int> array) 
{
    int curSum = 0;
    int maxSum = array[0];
    for(int i = 0;i<array.size();i++)
    {
        if(curSum<=0)
            curSum = array[i];
        else
            curSum+=array[i];
        if(curSum>maxSum)
            maxSum = curSum;
    }
    return maxSum;
}

題47 禮物的最大價值

題51 數組中的逆序對

題52 兩個單向鏈表的第一個公共節點

首先注意,兩個鏈表從第一個公共節點開始,之后的所有節點都是重合的,不可能再出現分叉,其拓撲形狀就像一個Y,而不可能像x。

方法一 使用兩個輔助棧,空間復雜度和時間復雜度都是O(m+n)

分別把連個鏈表的節點放入兩個棧里,這樣兩個鏈表的尾節點就位于兩個棧的棧頂,接下來從兩個棧頂的節點開始依次比較,直到找到最后一個相同的節點。

方法二 不再使用輔助棧,時間復雜度為O(m+n)

先遍歷得到兩個鏈表的長度,得到長的鏈表比短的鏈表多幾個節點。然后在較長的鏈表上先多走這幾個節點。再接下來在兩個鏈表上一起往后走,一直找到第一個相同的節點就是他們的第一個公共節點。

題63 股票的最大利潤

題68 樹中兩個節點的最低公共祖先

關于遞歸的思路,要先想清楚第n級和第n-1級的di

c++常用語法

vector

  • 兩個vector相連接,比如在a后面插入b,則為a.insert(a.end(),b.begin(),b.end())
  • vector賦值: vec2.assign(vec1.begin()+k,vec1.end())
  • 截取vec1中的一部分:vector<int>(vec1.begin()+m,vec.begin()+n)
  • vector去重
set<string> st(all_posible.begin(), all_posible.end());
all_posible.assign(st.begin(), st.end());

string

  • 截取str的第pos開始的連續len個字母組成的字符串 str.sub(int pos,int len),如果第二個參數缺省,則取到最后一個字母。
  • str.find(string sub, int i)返回str中第i個位置開始,第一次出現字符串sub的位置。經典例子,求字符串str中出現字符串sub的次數
int fun1(const std::string& str, const std::string& sub)
{
    int num = 0;
    for (int  i = 0; (i = str.find(sub, i)) != std::string::npos; num++, i++);
    return num;
}
  • 兩字符串相連想,直接str1+=str2.

set

  • 用別的容器對set進行賦值:```set<string> st(all_posible.begin(), all_posible.end());

#### stack 
#### 萬能頭文件

include<bits/stdc++.h>

using namespace std;

## 常用的小知識點
- 錯排公式:D(n)=(n-1)*[D(n-1)+D(n-2)]。[詳解](https://blog.csdn.net/bengshakalakaka/article/details/83420150)



?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,345評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,494評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,283評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,953評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,714評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,410評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,940評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,776評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,210評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,654評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內容