劍指offer總結

一、實現Singleton模式 二、二維數組中的查找:每行從左到右遞增,每列從上到下遞增,輸入一個數,判斷數組中是否存在該數 1 2  8 9  2 4  9 12 4 7 10 13  6 8 11 15 如輸入7: 小於第4列的9,則不可能在第4列;column-- 小於第3列的8,則不可能在第3列;column-- 大於第二列的2,則row++; 始終比較右上角的數,相等則返回。(每次查找都會剔除一行或者一列) 三、替換空格: (移動重複,想辦法減小重複,只移動一次!) 遍歷一遍字符串char[],得知空格數目,就可知道替換後的字符串長度,用雙指針p1 p2來從後往前移動字串 p1在p2的前面,指針同步移動(copy字符過去),可是p1遇到空格,p2就往前2步直到p2趕上p1,空格替換完畢 四、從尾到頭部打印鏈表:(先詢問是否能夠改變鏈表結構)    一、不改變:遍歷鏈表,值入棧,遍歷結束再值出棧    二、改變:用頭插法重建鏈表,再順序遍歷鏈表 五、根據前序和中序重建二叉樹:Java代碼 六、用2個棧實現隊列:Java代碼 七、旋轉數組求最小: 八、求斐波那契數列第n項    遞歸;直接用公式O(1);遞推O(n)  相似雙指針 把已經獲得的數列項保存起來 九、求二進制中的1的個數:    最優解法:(1100&1011=1000 能去掉最右邊的1)    intNumber(int n ){       int count=0;       while(n){       count++;       n=(n-1)&n;     }   } 常規解法: while(flag){    if(n&flag){      count++;    flag=flag<<1; } } 十、數值的整數次方: 要考慮負數(利用正數來求),0,正數 double f(double base,unsigned int e){   if(e==0)return 1;   if(e==1)return base;   double res=f(base,e>>1);   res*=res;   if(e&1==1)res*=base;   return res;  }//細節 十二、打印1-n的大數(轉化爲字符) 1三、刪除節點O(1)  值覆蓋p.data=p.next.data;p.next=p.next.next; 1四、調整數組使得奇數位於偶數前面(雙指針一前一後 判斷奇數p&1==1?) 1五、鏈表中的倒數第k個節點(雙指針  注意邊界) 1六、反轉鏈表 (1)雙指針 頭插法(2)三個指針pPrev pNode pNext 直接反轉鏈表 1七、合併2個排序的鏈表: ListNode* Merge(ListNode* pHead1,ListNode* pHead2){ if(pHead1==null)return pHead2; else if (pHead2==null)return pHead1; ListNode* pMergedHead=null; if(pHead1->Value<pHead2->Value){ pMergeHead=pHead1; pMergeHead->next=Merge(pHead->next,pHead2); } else { pMergeHead=pHead2; pMergeHead->next=Merge(pHead1,pHead->next); } return pMergeHead; } 1八、判斷樹B是不是樹A的子結構 struct BinaryTree{   int Value;   BinaryTree* left;   BinaryTree* right; }; bool HasSubtee(BinaryTreeNode* pRoot1,BinaryTree* pRoot2){ bool result==false; if(pRoot1!=null&&pRoot2!=null){ result=DoesTree1HaveTree2(pRoot1,pRoot2); if(!result) result=HasSubutree(pRoot1->left,pRoot2); if(!result) result=HasSubtree(pRoot1->right,pRoot2); } return result; } bool DoesTree1HaveTree2(BinaryTreeNode* pRoot1,BinaryTreeNode* pRoot2){ if(pRoot2==null)return true; if(pRoot1==null)return false; if(pRoot1->Value!=pRoot2->Value)return false; return DoesTree1HaveTree2(pRoot1->left,pRoot->left)&&DoesTree1HaveTree2(pRoot1- >right,pRoot2->right); } 1九、二叉樹的鏡像: void MirrorRecursively(BinaryTreeNode* pNode){ if((pNode==null)||(pNode->left==null&&pNode->right))return;         //先寫遞歸代碼,再添加退出條件 BinaryTreeNode* pTemp=pNode->left; pNode->left=pNode->right; pNode-right=pTemp; if(pNode->left)MirrorRecursively(pNode->left); if(pNode-right)MirrorRecursively(pNode-right); } 20、順時針打印矩陣 2一、包含min函數的棧    2個棧,一個數據棧,一個輔助棧,輔助棧中棧頂始終數據棧的最小元素,若進棧元素大於最小值,則重複加 入     最小值到輔助棧中,由於它是當前最小,若小於最小值,則加入該最小值到輔助棧中(2個棧元素數量始終一致) 2二、棧的壓入彈出序列(判斷第二個序列是不是第一個序列的彈出序列)     若是第二個序列中當前要判斷的元素恰好與棧頂元素相等,則直接pop出來,若是不等,則將第一個序列的 後面尚未入棧的元素入棧,直到將與之相等的元素入棧爲止,若是第一個序列的全部的元素都入棧了,尚未 找到與之相等的元素,則說明第二個序列不是第一個序列的彈出序列 2三、從上往下打印二叉樹 隊列,逐層遍歷 2四、二叉搜索樹的後續遍歷序列 2五、二叉樹中和爲某一值的路徑: 棧 先序遍歷 2六、複雜鏈表的複製:     (1)A->A'->B->B'...(另外一指針A->B)     (2)關鍵是A'->other=A->other-next;     (3)鏈表拆分 獲得copy的鏈表 2七、二叉搜索樹與雙向鏈表 (空) 2八、字符串的排列:全排列 2九、求數組中出現超過一半的數     (1)基於partition函數的O(n)算法,同快排的partition。會改變數組中數字的位置     (2)在遍歷數組的時候,保存2個數字,一個是數組中的數,一個是次數,遍歷到下一個數字時,若是和記 錄的數字相等,次數+1;若是不一樣則次數-1;若是次數爲0,則保存下一個數字,次數置爲1。O(n) 30、最小的k個數     (1)partition函數劃分,O(n)     (2)用最大堆做爲裝這k個數的容器(也能夠用紅黑樹這種數據結構),每次取出最大的數,遍歷完n個數 後,獲得最小的k個數。O(logk)          (能夠先判斷k>n/2則求前n-k大) 3一、求連續子數組的最大和  動態規劃 3二、從1到n整數中1出現的次數???? 3三、把數組排成最小的數(用字符串表示數字,解決大數問題??) 3四、醜數? (1)逐個判斷該整數是否是醜數 (2)建立數組保存已經找到的醜數??? 3五、第一次只出現一次的字符:    (1)掃描一遍字符串 int a[26]; a[字符-'a']++  hash的思想     (2)再次掃描字符串 輸出第一個知足 a[字符-'a']==1的字符 3六、數組中的逆序對:在數組中的2個數字若是前面一個數字大於後面的數字,則這2個數字組成一個逆序對     (1)暴力解法O(n^2){7 6 5}中有(7,6)(7,5)(6,5)     (2)歸併的思想??O(nlogn) 3七、2個鏈表的第一個公共子節點     最高效的解法:遍歷鏈表獲得長度m n 大的減少的=a,雙指針 長的先走a步,再一塊兒走,逐個判斷節點                  是不是同一個。O(m+n) 3八、數字在排序數組中出現的順序,二分法O(logn) 通常解法O(n) 3九、求二叉樹的深度  遞歸代碼最簡     拓展:判斷一棵樹是不是平衡樹(任一節點的左右子樹的高度差不大於1)後序遍歷每一個節點只訪問一次? 40、數組中只出現一次的數字(有2個這樣的數):要求時間O(n) 空間O(1)     (異或:相同數字異或爲0,任一數異或0爲自己)     倘若數組中只有一個數只出現一次,數組中數字逐個異或的結果就是隻出現一次的數字;     如今就要想辦法,把這2個只出現一次的數分到2個子數組中,就能獲得結果。     4異或6=100異或110=010   差異就是在第二個bit位上,因此咱們能夠把全部數字按這個原則分紅2組     4和6必定會被分到不一樣的組中,相同的數字會被分到同一組中。 4一、一個遞增排序的數組和一個數s,在數組中查找2個數的和正好是s,輸出任一對便可     通常解法是暴力O(n^2)  雙指針-首尾指針的解法是O(n)    拓展:打印和爲s的連續正數序列   15=1+2+3+4+5=4+5+6=7+8 打印(1 2 3 4 5)(4 5 6)(7 8 )       先造成清晰的解題思路,才能開始寫代碼;藉助上題雙指針的思路       最開始:small big 指向1 2   和爲3<9 big增大 123 和爲6<9 增大big 1234 10>9  增大small       2 3 4 =9 打印 再增大big  2 3 4 5 和14>9 減少small。。。找到4 5 =9      (循環退出條件:small<middle)其中middle=(1+sum)/2;        4二、翻轉字符串"I am a student."->"student. a am I"      2次翻轉 先整個reverse再單個單詞reverse     拓展:左旋字符串:輸入abcde 2  輸出cdeab     先ab->ba   cde-> edc 即abcde->baedc     baedc再reverse獲得cdeab(注意邊界 null) 4三、n個色子的點數? 4四、撲克牌的順子? 4五、圓圈中剩下的數字:     題目:0 1 2 3 ...n-1這n個數字排成一圈,從0開始每次從這個圓圈中刪除第m個數字,求這個圓圈最後剩 下哪一個數字?    有名的約瑟夫環問題 4六、?求1+2+3+...+n要求不能乘除法、for while if else swith case 條件判斷語句 4七、不用加減乘除作加法 4八、不能被繼承的類  java中用final  C++中沒有,能夠把構造函數設爲私有 4九、字符串轉換爲整數(本身想好特殊的測試用例) 50、樹中2個結點的最低公共祖先(問清楚需求,也許對方是故意漏掉條件考你的思路)
相關文章
相關標籤/搜索