個人秋招流程2

1.頭條
重構二叉樹
2.百度
快排,字符串編輯距離,青蛙過河。
逆序對問題
3.高德
雙快排變型(字符+數字; 荷蘭國旗問題),打印對角線數組=>順時針打印
4.京東
5.百度
跳馬問題,隨機概率權重的選擇
6.百度
旋轉數組的二分查找
7.競技世界筆試
召回率,曼哈頓距離,最小覆蓋子串
8.依圖筆試
區間覆蓋座標軸點數,(二分查找變型: 第一個大於等於target的index)
9.貝殼筆試
化簡結成後爲1+…+1/n>K; 殘缺的數字(難,放棄); 簡單的二維DP(鋸子斧子砍樹); 圖論
10.360筆試
立方體表面積,進制最小轉換
11.百度地圖面試
1.定義宏拿到類中變量的偏移 2.有效乘積運算符號的棧 3.滑動窗口某個IP出現最多的次數 4.相鄰的連續兩個數值差值不超過1,target存在的可能性?
虛函數表(繼承時的變化)+析構函數; BP的原理; feature_map的計算
11.騰訊筆試
12.美團面試
1.0/1揹包問題 2.DFS回溯搜索 3.LR類
13.京東筆試
消消樂,迷宮
14.快手筆試
tag打散,最長非重複子串,二元一次方程

其它:
https://www.nowcoder.com/discuss/205497

  1. sigmod和relu的區別?
    sigmod存在梯度消失的問題,產生原因在於: 參數w的更新梯度 = loss/輸出值的梯度 * 輸出值/激活函數的梯度 * 激活函數/w的梯度
    其中輸出值/激活函數的梯度 導數趨於零,導致只有靠近輸出層的參數纔能有比較好的訓練
    relu?
    輸出值/激活函數的梯度爲1,0 緩和梯度消失的問題。 缺點: 梯度爲0導致w不被更新 ==》 likealy-relu

  2. sigmod的取值範圍 (0,0.25]

  3. 分類問題爲什麼不使用迴歸MSE??

  4. 梯度消失和損失函數有關嗎?
    梯度值 = 三項乘積(鏈式法則),第一項是關於損失函數的loss。 但是梯度消失更多是不斷反穿過程中的消失,和損失函數關係不大。
    損失函數的選擇不是梯度消失的根本原因。

  5. 防止梯度消失/爆炸的方法? 1.爆炸: 預訓練+微調;梯度裁剪;L2正則(weight decay);BN層 2.消失:BN層;Relu激活函數;殘差網絡;LSTM而非RNN

  6. 深度學習防止過擬合? 1.BN+DropOut 2.圖像:數據增強 3.損失函數加入正則(optimazier+weightd decay) 4.bagging,subsample(特徵之間獨立同分布)

  7. stacking(e.g. stacked-Lstm)和blending

  8. 正則項: L0 參數矩陣非零元素個數,相比較L1正則更難優化求解所以選擇L1正則做特徵稀疏化

  9. 判別模型(大部分常見機器學習模型,根據X判別Y)和生成模型(樸素貝葉斯,聯合概率中較大的爲預測值)

  10. 蘇格拉底麥穗問題 1/e作爲切分點,記錄前N/e中最大的麥穗

  11. LR和Adaboost區別?(LR更新w來靠近錯誤樣本? 而Adaboost增加錯誤樣本出現的概率?) AdaBoost和GBDT區別?

  12. 概率題=隨即發生器,rand5(),剪繩子,送報紙

  13. 正定:實對稱矩陣,且滿足所有特徵值都是正的。 ==> X’AX > 0

  14. 半正定: X’AX >= 0

  15. 2個33的卷積核的感受野 == 55的卷積核的卷積核

  16. L1正則: 數據分佈先驗是拉普拉斯 L2正則: 數據先驗分佈是高斯

  17. 協同過濾

UserCF: 興趣相近的TopK其他用戶喜歡的物品推薦給當前用戶
更依賴於相近興趣用戶的共同的行爲 => 欠缺個性化,實時性差(用戶的新行爲不能及時導致推薦結果變化)
ItemCF: 把用戶歷史觀看過的相似物品做召回
行爲過物品很多的話,召回更多的相似物品,可挖掘的長尾信息也更多 => 個性化強,實時性強(用戶新行爲能很及時導致召回相似的物品)

目的: 當用戶在其他頻道瀏覽完長視頻,切換到小視頻頻道時,也能很快給他推薦相似的視頻
任務: 拿到融合所有信息的item-item的倒排表。最後只需要把小視頻召回的長視頻ID在倒排表裏面刪除
用戶:歷史行爲==> pair對,統計出現次數作爲這個pair對的相似度。獲得item-item倒排表,對於item再取topK即可。實際使用過程中還會pair對出現次數過多的做懲罰 + 歸一。
e.g. pair對出現的次數/(這兩個元素出現的次數總和)
1.用戶的長視頻信息和小視頻信息做融合,按照時間的先後排序。獲取視頻的倒排表,再把value中的長視頻刪除掉。 這樣就可以通過長視頻的喜歡(來自用戶畫像)來召回小視頻了。
2.重構下scala代碼,輸入時候把長視頻加符號標識,輸出物品倒排表時把value中的長視頻刪除,key中長視頻刪除特殊符號
3.嘗試過優化過排序方式,長視頻觀看時長,長視頻觀看時長/用戶長視頻觀看時長中位數。

和word2vec原理類似的。
1)構造樣本的時候,拿用戶的觀看歷史,其實就是一連串的視頻ID,作爲sentence,段落。把所有的用戶的觀看視頻歷史行爲,作爲corpus語料庫。再用cbow或者skip-gram模型做訓練。就得到視頻ID的embedding。
2)實際使用中限制[5,500]長度,避免不活躍或者過於活躍的用戶
2)實際使用過程中,還會加入視頻的一些標籤作爲side-information一起做訓練(自拍 withindex)。來拿到一些標籤的embedding,當出現不在詞表裏面的視頻id,可以把它的標籤數據做平均,緩解冷啓動問題
3)優化: 出發點: 用戶不同session下感興趣的內容不同的。預測的滑動窗口內的視頻類型一致性
3.1) session的時間選取,所有視頻間隔從小到大排序,累計概率的95分位,大約是700s來切割用戶的歷史行爲。
3.2) ABtest幾個主要指標有提升,上線。

Cbow: 把中心單詞周圍的單詞的embeding做平均,去預測中心單詞,梯度更新時也是平均分配到周圍單詞。低頻的單詞預測效果不夠準確。
Skip-gram: 每一箇中心詞去預測周圍所有單詞,做K遍預測,embedding更準確。 特別是當語料庫有大量低頻次單詞時
#
1)索引的概念: 精確匹配 l2距離或者內積距離作爲index; 其他index都是對向量維度壓縮後的非精確匹配
2)聚類: KNN=KD樹;思路類似hashmap,把相同的key值放在同一個單元中,再去搜索時候只需要在某個單元裏和它相鄰的單元裏搜索

  1. 每一個向量有自己的索引
  2. 基礎算法: PCA降維 or ProductQuantizer編碼解碼 + KNN分類 + kd樹 or LSH 搜索(相同key,或者臨近的key中搜索)
  3. 選擇合適的index? 精確匹配:flat Memory: HNSWx(內存足夠,mem=(d * 4 + x * 2 * 4),x是向量的索引)
  4. 搜索查找算法: KD樹 1.尋找每一維度的中位數劃分空間 2.二叉樹每一層對應同一維度
  5. LSH局部敏感哈希算法 == 降維之後評判相似度(前提: hash函數的轉換前後,依然能表徵相似度)

和item2vec區別點主要是在於構造樣本集的方式不同

  1. 構建圖,節點是ID,有用戶歷史相連的行爲就構造邊 如何構建邊??
  2. 由一個節點出發,deep walk,步長 => p,q概率值來確定BFS DFS遊走
  3. 實際使用時候=> 選擇無向圖還是有向圖;限制一個節點的度數(作爲對於熱門物品的懲罰);實際使用中偏向於DFS
  4. 所有節點都出發一次,但是隻有7天的數據數據量偏小
    #
    1)基於內容標籤&精品池; 用戶畫像的標籤
    2)LDA主題聚類 等等聚類算法
    3)YoutubeDNN NN模型 ==> embeding layer + 手工特徵 ,通過BP反向訓練embeding layer
  5. https://zhuanlan.zhihu.com/p/58160982 (不錯的文章)
  6. Transformer & self-attention ???
  7. FM直觀理解: 每一個特徵都有自己的embedding,時間效率降低爲O(K*N) 原來直接做二階組合:O(N^2)

解決的問題: 商品和商品的相關性矩陣,某個用戶對於物品的評分。 從中抽取topK的商品推薦給用戶,要求:商品和用戶之間相關性強,商品之間具有多樣性。
傳統方案: 直接抽取Topk(沒有考慮商品之間的多樣性)
DPP: 抽樣過程,存在實對稱的,半正定矩陣。刻畫抽取子集的概率子集對應的行列主子式的值
把商品的embeding分解成兩個向量ri,fi. fi是商品自身的embedding。 行列式的值=(ri)^2 * det(物品的相似度矩陣)
含義: 抽取10個商品
用戶對於這是個商品的評分的練乘 * 物品相似度矩陣的行列式值(越相似的物品其行列式值越小==對角線的乘積-物品之間的相似度)
==> 用戶對於抽取子集整體比較喜歡, 子集之間的相似性還比較小

NP hard抽取最優的子集
greedy: 練乘,取log變成連加。==》log(det(Y)) 每次選擇信息增益最大的加入推薦集合

#22. 論文 NN模型關鍵點,Encoder_三輸入_concat_matrix(差,點積),DeCoder_stacked_LSTM, 降維可視化的聚類
1)目標: 同一首歌的亂序的三個音樂片段,重排序恢復成正常順序。
2)關鍵點在於: NN模型區分三個片段整體相似度,相似度越高越接近正常順序。
3)AAAI原論文:順序相連的片段頻譜圖作爲正例樣本,不相連的頻譜圖作爲負例樣本。正常排序是123,12正樣本,13負樣本。轉化成一個分類問題,NN模型輸入兩個片段,判斷兩個片段是否相關。三個片段有6種排列組合,每個排列兩個pair對,把相似度值求和,再從所有排列中選取選擇最大得分作爲最終排序結果。
4)改進: 主要是兩個改進點Encoder,Decoder。
Encoder: 原論文是兩個片段的頻譜圖,我改成輸入三個片段頻譜圖,有了兩個pair對。特徵提取還都是用的CNN。計算片段相似度矩陣時,
手上兩個相似度矩陣,以及他們分別做差,做點積。再concat起來再給Docoder做處理(e.g. batchsize256(256*4))。這麼做目的就是爲了人爲增加輸入層的信息。
Decoder: 原論文直接就是的三層全連接做分類。我先堆疊了三層LISTM,目的:在輸入的信息中做時間維度的特徵提取,再走全連接層。
主要是這兩個Encoder,Decoder方面的改進。
5)最後把準確率ACC,Loss下降趨勢和原論文做了對比。 還把最後隱層的特徵取出來做了可視化,對比下原論文和我的模型的分類效果更加聚集。

在原論文上改進了encoder,decoder的結構。
input:音樂的頻譜圖,對於8秒的音樂片段,librosa將其轉化爲頻譜圖。相當於圖片的x軸是時間維度,y軸是頻譜,聲音的高低。
Encoding:原論文是輸入兩個片段,拿CNN提特徵把feature map(batchsize * channel * time)用來計算餘弦相似度(batchsize * time * time)。 我改成輸入三個音樂片段去算整體的相似度,
Decoding:隨着時間維度 Lstm特徵提取,max_pooling(得到batch * time * 1),在走MLP

  1. xgb節點劃分準則,時間複雜度,gain 重新看下論文吧
  2. 樣本不平衡? 重新採樣(增大正樣本數量 過採樣smote/丟棄負樣本數量 欠採樣); 懲罰權重weight=>logloss完全沒法看; 模型做集成,增加差異性
  3. 特徵不平衡??
  4. 樣本缺失?
  1. 訓練中特徵缺失,分別放入左右子樹計算信息增益,把缺失特徵歸於信息增益大的子樹。測試時候同一個特徵出現缺失就把樣本導向訓練時候的劃分方
  2. 僅僅在測試樣本有缺失,默認走右
  3. ID3訓練時缺失: 丟棄後重新計算信息增益;
  1. xgboost常見參數:
    1.樹深 & 樹的節點個數
    2.正則項: L1正則和L2正則 默認爲1
    3.信息增益:γ
    4.shrink: 0.01
    5.bagging & feature subsample
    6.不平衡數據: weight
  1. L1/L2正則: L2正則是關於W的圓形的解空間,L1正則是多邊形的解空間。 L1和目標函數最優解W*更容易碰撞出稀疏解
  2. gbdt xgb lgb
  3. gbdt
    1)boosting模型,擬合前一個基學習器的一階導數。 當基學習器的Loss是MSE時,對於f(x)整體求導,得到是真實值和預測值的殘差
    2)對於異常值敏感 <==> 使用MSE作爲Loss的通用缺點
  4. xgb:
  1. Loss函數二階泰勒展開,引入前一個基學習器的一階導二階導,對於當前要學習的目標值計算更準確 (MSE是一樣的?)
  2. 正則項: 葉子節點個數L1正則 + 葉子節點得分的L2正則
  3. shrink + subsamle(獨立同分布最好)
  4. 剪枝 γ信息增益的最小值
  5. 過擬合? 1.葉子節點數量 2.shrink 3.W*的L2正則 4.特徵選擇 4.bagging/subsample 5.數據增強
  6. 時間複雜度 1.每一個特徵值做排序 dNlogN 2.樹深K層 ==> K * d * N*logN
  7. 分類: 擬合真實標籤和預測概率(sidmod壓縮)的差值。初始化h0=log(p正樣本/1-p), 前一個樹的輸出做sidmod變換
  8. 缺失值(訓練、測試),連續值處理
  9. 並行: 1.每個樣本的負梯度值 2.最優特徵&最優劃分點 3.預測階段
  1. lgb
  1. leaf-wise
  2. goss
  3. one-hot特徵
  4. 直方圖
  1. 常用參數

  2. xgb控制過擬合的方法? l1 + l2

  3. cart樹 gini index?

  4. LR和SVM區別:

  1. 線性可分: LR迭代求解得到w* SVM引入margin拿到最優解
  2. 線性不可分: kernel函數計算LR需要計算所有點, SVM的對偶形式中只有αi不爲零的支撐向量採用kernel核函數計算
  1. LR優化 並行? SVM優化?
  2. SVM是需要特徵做歸一化的 (線性模型: 不同特徵之間的量級保持一致) ==> 樹模型是變量的分佈
  1. 高維空間是線性可分的
  2. 高維空間的點積計算 ==> 在低緯度的空間計算其核函數
  3. 線性核函數: 線性可分情況;特徵數量大(線性覈計算更快) 徑向基:高斯核函數 線性不可分; sigmod核函數: tanh
  1. 優化器Adam 動量:參數向量會在任何有持續梯度的方向增加速度 Adam:learning rate是衰減的,適應性的更新

  2. 自己的最有成就感的事情

  3. 評價指標? 分類(樣本不平衡問題)ACC,Recall,F1, 迴歸(離羣點的噪聲問題)RMSE,MAPE(|y-y’|/y), 排序問題 AUC

  4. 損失函數? 分類: 0-1,邏輯迴歸,交叉熵,hinge 迴歸:MSE,絕對值,Huber

  5. 機器學習過擬合? 1.數據增強 2.模型簡單化: 損失函數加正則項; 網絡 BN+Dropout+殘差結構 3.工程: bagging; 特徵選擇得到稀疏解

  6. pythorh訓練流程?

  1. dataloader = DataSet(init,length,get_item), collection(batchList ==> numpy). shuffle,drop_last,num_workers
  2. NN.moudle = init(參數初始化,layer聲明),forword調用
  3. 創建 Loss(交叉熵) + optimizer(Adam)
  4. epoch,generator = optimizer.zero_grad()清空梯度緩存; 計算ouput; lossFunc(outputs,var_label);loss.backward()反向轉播完畢; optimizer.step()更新參數矩陣

###############大數據
9. hadoop框架
hdfs => mapreduce => hbase/hive
10) 第一層: (運行在kernel)文件管理系統hdfs; nameNode類似hashmap,存儲每一個文件&對應的機器; dataNode存儲數據塊,負責讀寫IO操作。 如何保證讀寫一致性?
11) 第二層: mapreduce並行計算框架,mapper做鍵值對+shuffle(mapper的數量不是人爲給定的),reducer做數據處理
12) 第三層: Hbase(No-sql數據庫),hive(類似sql去做MR讀取數據)
13. spark框架
driver: 主進程,application exactor:多CPU core執行
實時性。 memmap將數據做磁盤到內存映射; 定義RDD結構; driver,exactor數據處理
14. hash分桶TopK
有10000000個記錄,這些查詢串的重複度比較高,如果除去重複後,不超過3000000個。一個查詢串的重複度越高,說明查詢它的用戶越多,也就是越熱門。請統計最熱門的10個查詢串,要求使用的內存不能超過1GB。
有10個文件,每個文件1GB,每個文件的每一行存放的都是用戶的query,每個文件的query都可能重複。按照query的頻度排序。
有一個1GB大小的文件,裏面的每一行是一個詞,詞的大小不超過16個字節,內存限制大小是1MB。返回頻數最高的100個詞。
提取某日訪問網站次數最多的那個IP。
10億個整數找出重複次數最多的100個整數。
搜索的輸入信息是一個字符串,統計300萬條輸入信息中最熱門的前10條,每次輸入的一個字符串爲不超過255B,內存使用只有1GB。
有1000萬個身份證號以及他們對應的數據,身份證號可能重複,找出出現次數最多的身份證號。
15. 思路1: hash分桶統計TopK
16. 思路2: bitmap做hashtable (e.g.整數集合求交集)
17. 思路3: trie樹

####### 比賽

  1. 樣本不平衡, calss_weight or smote算法(過採樣) or 欠採樣()
  2. 點擊量特徵 交叉
  3. ESIM?
  1. Input-Encoding: EmbeddingLayer+Bi-LSTM
  2. Interaction & Enhanced
  3. 原始矩陣的乘積Eij; 再根據Eij分別對於行、列計算softmax;和另外一個原始矩陣做點積) && 增強 【A,A’,A-A’,A*A’】
  4. A’ 是通過a1是b1,b2,b3…單詞做加權平均得到的
  5. 每個單詞分別對於另一個句子進行對齊操作,然後每個單詞都可以根據對其結果得到一個由另一個句子的每個單詞的向量加權求和得到的新的向量表示
  1. Decoding bi-lstm + 多層全連接
  2. tf-idf的缺點? 1.tf=>bm25 2.丟失位置信息=>ngram彌補
  3. glove2vec
  1. 單詞共現矩陣,單詞i和它的滑動窗口中單詞j的全局共現的次數 ==> Xij/Xi表示單詞j出現在單詞i的上下文的概率
  2. 目標函數: 從共現矩陣隨機採樣,計算wi*wj+bi+bj 去學習目標log(Pij)
  3. 設計權重函數
  4. 得到word embedding
  1. 特徵標準化/歸一化方法?
    目的: 梯度下降計算最優解的方向更直接,計算更快
    方法: 最大最小標準化, Z-socre(x-均值)/方差; 非線性:反正切函數
  2. attention?

推薦系統

  1. FM
    linear regression + 二階特徵交叉
    問題:
    1.交叉特徵的wij很難被充分訓練;
    2.wij參數量級爲N(N-1)/2
    改進:
    1.one-hot後每一維特徵擁有自己的隱向量V,k維 ; wij=vi*vj的內積 ; 參數量級爲N * K
    2.時間複雜度 ==> 直觀上O(N^2) ==> 公式推導O(N)
    本質:
    在對稀疏特徵做embeding表達 ==> 公式推導爲O(N) ==> 只要xi特徵值不爲零,即可訓練其隱向量V

  2. BFS做跳馬問題:

二維數組bool used
二維數組int step
*******************************************理解BFS的兩重For循環
while(!queue.empty()){
if queue.front == 終點
return step
queue.pop()

for(可達的8個點 push=>  queue){
    if(沒有遍歷, step = queue.top.step+1)
        queue.push
        used = true
 }

}

*******************************************理解DFS
DFS(source):
s <- new stack
visited <- {} // empty set
s.push(source)
while (s is not empty): //開始stack.empty()
current <- s.pop()
if (current is in visited):
continue
visited.add(current)
// do something with current
for each node v such that (current,v) is an edge: //當前點的可達點加入stack 非常類似於BFS啊
s.push(v)

******************************************二分查找 (數組中第一個大於等於target的位置 仔細理解 依圖筆試第一題)
public int bsearch(int[] a, int n, int value) {
int low = 0;
int high = n - 1;
while (low <= high) {
int mid = low + ((high - low) >> 1);
if (a[mid] >= value) {
if ((mid == 0) || (a[mid - 1] < value)) return mid;
else high = mid - 1; //a[mid-1]<=value 繼續向左移動
} else {
low = mid + 1;
}
}
return -1;
}
****************************************二分查找 完全二叉樹的最後一層的最右側節點
BinaryTreeNode
getLastNode(BinaryTreeNode
root)
{
if(!root || (!root->left && !root->right))return root;
int depth = 0;
BinaryTreeNode
curNode = root;
while(curNode)//計算二叉樹的深度
{
depth++;
curNode = curNode->left;
}
int level = 0,tmpDepth = 0;
while(root)
{
level++;//當前遍歷到哪一層,跟節點是第一層
if(level == depth)break;//防止右子樹爲空
curNode = root;
if(curNode->right)
{
BinaryTreeNode
pCur = curNode;//當前節點的父節點
curNode = curNode->right;
tmpDepth = level + 1;
while(curNode->left)
{
tmpDepth++;
pCur = curNode;
curNode = curNode->left;
}
if(tmpDepth < depth)root = root -> left;//二分查找左子樹
else if(!pCur->right || pCur->right == curNode)return curNode;
else root = root->right;//二分查找右子樹
}
else root = root->left;
}
return root;
}

****************************************************************根據前序遍歷構建二叉樹
void preOrder(node * & root,int & index)
{
if(index>=input.length()){
return ;
}
if(input[index]==’#’){
root=NULL;
index++;
}
else{ // 對於root節點的操作
root=new node;
root->data=input[index];
index++;
// 前序遍歷的遞歸
preOrder(root->lchild,index);
preOrder(root->rchild,index);

}

}
*************************************************************** 堆排序
1.構建大頂堆
for(k=n/2; k>1; k++)
sink(arr,k,n)
1.1. sink函數
while(k*2 <= n)
尋找子節點的最大值 j
if 需要將父節點k值做交換
將節點k和其子節點的最大值做交換(下沉)
else
break
2.while(n>1) 將最大值放在數組末尾
arr[1],arr[n];
n–;
sink(arr,i,n)
************************************************************************鏈表

void PrintListFromTailToHead_R(ListNode* head)
{
if (head){
if (head->next)
PrintListFromTailToHead_R(head->next);
cout << head->val << " "; //遞歸形式逆序打印
}

*********牛頓迭代法 計算平方根
f(x)=x^2 - a
xn+1 = xn - f(xn)/f’(xn) 迭代計算根root
#
AUC計算函數
分母: 正樣本個數*負樣本個數
分子: 分母pair對中,預測正確+1,分數相等+0.5,預測錯誤+0

************************************************************ 數組問題
題目: 數組48,54,73,74,33,81

  1. 螺旋打印 top bottom left right四個變量; while循環停止條件; 打印前的判斷條件
  2. 傾斜打印數組 for遍歷j–;
  3. 數組順時針翻轉90° (上下翻轉 + 右上角左下角交換)
  4. 矩陣置零(set 存儲行,列)
  1. 矩陣二分查找 完全升序 mid_val = matrix[mid/col][mid%col] 除以列,取模列拿到matirx的中位數 74
  2. 矩陣二分查找 上下,左右分別升序 (從右上角開始)
  3. 旋轉數組查找旋轉點 (while 記得break )
  4. 有重複元素的旋轉數組二分查找 (nums[left] == nums[mid]) && (nums[right] == nums[mid]) 單獨O(N)遍歷
  5. 有重複元素有序數組中target出現的次數 (二分查找)
  6. 亂序數組中第一個缺失的數字 (leetcode 41 swap)
  1. 偶數次出現刪除, stack

  2. 有序數組重複元素刪除 pointer

  3. 有序數組重複元素最多出現兩次 pointer

  4. target元素移動到數組末尾 快排=>交換target和不等於target的元素

  5. 注水容器問題 - 兩道

  6. 荷蘭國旗

  7. 1~N個數字,有一個數字重複1次,最後有N+1個元素。(要求不改變順序) 找出這個數字?
    鴿巢原理,每次統計小於mid的val的個數count, cout>mid, high=mid. 最後返回的high是一個index!! 正是重複的元素val!!

  8. 如果此數字出現超過一半?

  9. 擋板內的最大水量問題 1.頭尾指針向中間移動 2.area=(leaf-right)*(h[left],h[right])

  10. 直方圖的最大水量問題 1.頭尾指針 2.max_left表示頭指針移動過程中左側高度的最大值 res+=max_left - h[頭指針]

  11. 歸併時間間隔 先按照start排序,再比較end和next.start大小(不斷change cur.end值)

  12. 新插入時間間隔 遍歷一次

  13. 1.跳過cur.end < new.start,直接push到ans 2.while(cur.start <= new.end){ new.start=min(cur,new); new.end=max(cur,new)} => 只需要push一次ans.push(new)

  14. 楊輝三角 初始化:兩側邊界爲1

  15. 長度爲L的繩子最多覆蓋的點數 ==> fast,slow遊標 if(arr[fast]-arr[slow]<L) fast++

  16. N!有多少位0 ==> N包含5,25,125的數目 ==> 相當於計算N含有5的因子數量

************************************************************鏈表問題

  1. 刪除倒數Kth指針 1.fast比slow多走K步 2.如果fastNULL, return head->next (K長度鏈表長度了,刪除頭指針)
  2. 轉置鏈表 1.tmp保存head->next 2.head->next指向pre 3.更新head=tmp,pre->next=head;
  3. 轉置鏈表 遞歸版本(參數: pre , cur)
  4. 間隔兩個步長交換元素 1.遞歸形式 2.非遞歸形式
    非遞歸形式= while(head,head->next) 1.tmp保存head->next 2.head->next指向第三個節點 3.tmp->next指向head 4.前一個節點pre->next指向tmp 5.更新pre,head
  5. 鏈表取出偶數序號元素 (pre指針不斷添加; fast = fast->next-next移動兩步)
  6. 升序鏈表轉BST 遞歸:helper(L* start,L* end) 尋找mid位置做切割
  7. 鏈表轉化爲1,n,2,n-1…形式 1.尋找切割點 2.第二段鏈表轉置 3.交叉添加
  8. 兩鏈表交點 while(p1!=NULL && p2!=NULL &p1!=p2)
  9. 奇數放在偶數前面 (ListNode* pre1,ListNode* pre2; 奇數偶數每次移動兩個步長)
  10. 數字相加 carried變量保存進位

**********************************************************stack

  1. 括號有效性
  2. 最長有效括號 stack存儲無效index,
    如果遇到),消除stack.top()對應的"("==》1.此時stack爲空,則有效長度=i+1 2.stack不爲空,有效長度=i-stack.top()
  3. 前序遍歷,中序遍歷,後序遍歷
  4. 1.pre=root 2.while(!s.empty()||p!=NULL){} 2.if(p!=NULL){s.push§;p=p->left} 3.else{ 3.1 TreeNode*top 3.2 vec.push(top->val) 3.3 p=top->right}

**********************************************************二叉樹

  1. 中序遍歷
  2. 注意: 此時的top是左子樹的最左邊節點
    TreeNode* p = root; //init
    while(!rootStack.empty() || p!=nullptr){
    if(p!=nullptr){
    rootStack.push§; //0. stack.push
    p=p->left;
    }
    else{
    TreeNode* node = rootStack.top(); // 1 stack pop
    rootStack.pop();
    inorder.push_back(node->val); //2 vec.push
    p = node->right; //3 更新p
    }
    }
  3. 二叉搜索==>中序遍歷的遞增
  4. 記錄根節點到葉子節點的路徑和==sum? helper(TreeNode* root,二維數組ans,當前回溯路徑Path,當前目標target)
  5. 二叉樹的直徑 對於每一個節點記錄其左右子樹的深度和 最終選取最大值
  6. 僅僅根據前序遍歷帶"NULL"構建二叉樹?
  1. 對稱樹 輔助函數,helper(left->left,right->right) && helper(left->right,right->left);
  2. 平衡二叉樹 1.輔助函數計算樹深 2.或者類似後續遍歷的遞歸寫法 left遞歸,right遞歸,判斷left-right的差值,return max(left,right)+1
  3. 子樹 1.helper先判斷兩個樹是否相同 2.原函數遞歸判斷A->left,B || A->right,B
  1. 鏡像樹
  2. 前序遍歷帶# 類似於前序遍歷的流程,TreeNode* build(vector&arr,int& index)
  3. 前序&中序
  4. 排序數組構建二叉搜索樹 數組108題 (1.helper(vec&array,int low,int high), 選擇mid_val作爲當前root節點 2.helper的停止條件: if(low < high) return;)
  1. 最大深度 4行
  2. 最大直徑 類似後續遍歷,root節點處理左右子樹和
  3. 路徑和 pathSum(TreeNode* root, int target, vector&path,vector<vector>& ans)
  4. 最近公共父節點
  1. 二叉搜索樹的最近公共父節點 參數: TreeNode* root,p,q
  2. 第K小的值
  3. 每一個節點的val修改爲所有大於其的和
  4. 1~N構成的所有BST 1.from-to的循環 2.循環內部的後續遍歷

**********************************************************揹包

  1. 0/1揹包 dp[i][v] = min or max (dp[i-1][v],dp[i-1][v-cost]+val)
  2. 完全揹包 修改爲 dp[i][v-cost]+val
  3. 多重揹包 F[i,V] = sum(F[i-1,V-k*costi]) 0=< k <=Mi (此題限制次數: Mi=N/costi)
  4. 正則表達式匹配
    1)當 *s==’\0’ && *p==’\0’ return true;
    2)當 *s!=’\0’ && p==’\0’ return false;
    3)當 (p+1)!=’'時, 判斷p,s是否成功匹配。 P==s || p==’.’&&s!=’\0’ ==> 遞歸判斷 (s+1,p+1)
    4)否則 由於此時
    (p+1)==’
    ’,涉及多種狀態:
    4.1) 如果此時
    p和
    s可以匹配上,方式3 ==> 遞歸 (s,p+2) || (s+1,p+2) || (s+1,p)
    4.2) 如果此時
    p,*s不匹配, 遞歸 => (s,P+2)
    5.其他 return false
  5. 正則表達式DP

**********************************************************DFS/BFS/回溯

  1. 小島的數量 (DFS 經過的1標記爲零)
  2. 矩陣字符是否能構成某單詞 (DFS 1.到達(str+1)=’\0’,True 2.grid標記’\0’ 3.DFS查找上下左右 4.回溯grid標記爲原有字符
  3. beginWord通過已有的string list轉化爲Endword需要多少步? ==> BFS
  4. 被包圍的元素同質化 (DFS 1.從邊界出發將可達點置爲1 2.最終非’1’元素置位’x’)
  5. 分割字符串,要求子串全是迴文字符串,有多少種分割方式? > 子集問題的變型
    #######
    1.圖中判斷點是否可達? dfs(Graph,int start,marked[]) 1.標記s已訪問 2.s所有相連節點(循環遍歷)中未被marked的節點做遞歸
    2.圖中獲取start到end的路徑? edgeTo[] for(start相鄰節點) if(相鄰節點
    false){ 1.edgeTo[相鄰節點]=start; 2.dfs(G,相鄰節點)}
    3.圖中獲取最短路徑? BFS while(Q.empty){ 1.Q.front 2.for(top節點的所有相鄰節點){2.1 mark 2.2edgeTo[相鄰節點]=top 2.3.加入Queue}}
    4.最小生成樹? Prim 1.從某一個點出發選擇所有未被遍歷的邊權重最小邊 2.數據結構: priority_queue + marked[]
    5.最小生成樹? Kruskal 1.貪心遍歷有效的最低權重邊 2.數據結構: priority_queue + union_find(如果邊的兩個頂點不在同一個連通集中則是有效的)
    6.單源最短路徑?
    0.Dist[i]保存start點到i的路徑,init
    1.第一層循環 for(i=1)所有頂點
    2.for循環更新: newP直接相連的頂點dist[j] 更新 dist[j] = dist[newP] + edge[newP][j]
    3.並列for循環: 挑選dist[k]最小的點 mark[k]=True

************************************************************排列問題
題目: 數組31
https://leetcode.com/problems/next-permutation/discuss/13867/C%2B%2B-from-Wikipedia

  1. 下一個排列 1.從右往左找到第一個非遞增的index 2.從右往左找到第一個大於index的val的index’ 3.交換index,index’ 4.轉置index,end的元素
  1. 無重複元素
    (arr,ans,tmp) 1.tmp.size()==arr.size() 2.回溯循環每次都是從零開始 3.循環內 判斷arr[i]是否在 tmp中使用
  2. 有重複元素
    (arr,ans,tmp,used) 1.sort 2.回溯循環從零開始 3.循環內判斷:(used[i] || (i>0&&arr[i]==arr[i-1]&&!used[i-1]))
  1. 無重複元素
    (arr,ans,tmp,start) 1.每輪ans.push(tmp) 2.回溯的循環從start開始 3.回溯start+1
  2. 有重複元素
    (arr,ans,tmp,start) 1.~ 2.~ 3.加一個判斷 if(i!=start && origin[i]==origin[i-1]) continue;
  1. 無重複元素 & 每一個元素可以選取多次
    (arr,ans,tmp,start,target) 1.if target<0,tmp加入ans 2.從start開始循環 3.backtrack(ans,tmp,origin,target-origin[i],i); 注意接着從i開始循環 而非i+1
  2. 有重複元素 & 同一個元素只能選取一次
    (arr,ans,tmp,start) 1.~ 2.~ 3.加一個判斷 if(i!=start && origin[i]==origin[i-1]) continue; 4.backtrack(ans,tmp,origin,target-origin[i],i+1);

************************************************************概率題目

  1. 小球left or right下落到N層的概率 ==> 楊輝三角
  2. 8個球分成3,3,2稱兩次 即可確定重量輕的球

*************************************************************動態規劃

  1. 矩陣路徑問題
  2. 最大的sequence的和問題
  3. 最長迴文子串 dp[i][j] [i,j]區間是否爲迴文
  4. 最長01個數相等的子串substring 1.將0轉換爲-1 2.求區間和爲0的最長區間 3.dp[i][j] = dp[i+1][j-1]+arr[i]+arr[j]
  5. 最長的非重複字符的substring fast-slow
  6. 矩陣中1構成的最大的正方形 右下角dp
  7. 矩陣中1構成的最大的長方形
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章