待處理
- 極大似然的原理
- SVM 原理
- L1和L2的區別,以及各自的使用場景
- 為什么梯度是函數變化最快的方向 https://zhuanlan.zhihu.com/p/24913912
去除字符串連續字符
遞歸的去除字符串中連續的 ac 和 b
#include <iostream>
#include <vector>
#include <stack>
using namespace std;
int main() {
string s {"aaccaptgbcaca"};
if (s.empty()) {
return 0;
}
stack<char> st;
int cursor = 0;
while(cursor < s.size()) {
char ch = s[cursor++];
if (st.empty()) {
st.push(ch);
} else {
if ( ch == 'b') {
continue;
} else if (st.top() == 'a' && ch == 'c') {
st.pop();
} else {
st.push(ch);
}
}
}
vector<char> ch(st.size());
for (int i = st.size()-1; i >= 0; i--) {
ch[i] = st.top();
st.pop();
}
for (auto& e : ch) {
cout << e << " ";
}
return 0;
}
將一個字符串變成數字
#include <iostream>
#include <sstream>
using namespace std;
int main() {
string s = " 1234js9";
stringstream ss {s};
int num;
ss >> num;
cout << num << endl;
return 0;
}
鏈表加法
leetcode 2
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode dummyHead(-1);
// 凡是這種要構建新鏈表的, 貌似都要搞一個 dummyHead 比較簡單
ListNode *p = &dummyHead;
int partSum = 0;
while (l1 != nullptr || l2 != nullptr) {
if (l1) {
partSum += l1->val;
l1 = l1->next;
}
if (l2) {
partSum += l2->val;
l2 = l2->next;
}
p->next = new ListNode(partSum%10);
p = p->next;
partSum /= 10;
}
if (partSum != 0) p->next = new ListNode(partSum);
return dummyHead.next;
}
};
判斷二叉樹是不是二叉搜索樹
leetcode98. Validate Binary Search Tree
方法 1
中序遍歷樹, 查看遍歷過程中是否是升序
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
bool isValidBST(TreeNode* root) {
TreeNode* p = root;
if (!root) return true;
stack<TreeNode*> st;
long pre = LONG_MIN;
long cur = LONG_MIN;
bool isValid = true;
while (p || !st.empty()) {
if (p) {
st.push(p);
p = p->left;
} else {
cur = st.top()->val;
if (cur <= pre) {
isValid = false;
break;
}
pre = cur;
p = st.top()->right;
st.pop();
}
}
return isValid;
}
};
方法 2
根節點的值大於左子樹的最大值, 小於右子樹的最小值,
作為葉子節點來說, 以左葉子節點來說, 左葉子節點要
- 滿足父節點的約束;
- 小於其父節點的值;
class Solution {
public:
bool isValidBST(TreeNode* root) {
return isValidBST(root, LONG_MIN, LONG_MAX);
}
bool isValidBST(TreeNode* root, long min_val, long max_val) {
if (!root) return true;
return (root->val > min_val) && (root->val < max_val) &&
(isValidBST(root->left, min_val, root->val)) &&
(isValidBST(root->right, root->val, max_val));
}
};
將二叉搜索樹轉換成雙向鏈表
遞歸解法
解法很經典, 好好揣摩.
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
#include<iostream>
#include<stack>
using namespace std;
class Solution {
public:
TreeNode* res;
TreeNode* Convert(TreeNode* pRootOfTree)
{
if(pRootOfTree == nullptr) return nullptr;
TreeNode* pre = nullptr;
convertHelper(pRootOfTree, pre);
return res;
}
// *& 很重要, 必須使用引用, 否則當前 pre 並沒有更新到最新位置
void convertHelper(TreeNode* cur, TreeNode*& pre)
{
if(cur == nullptr) return;
convertHelper(cur->left, pre);
cur->left = pre;
if(pre) {
pre->right = cur; // 用於處理鏈表的起始位置
} else {
res = cur;
}
pre = cur;
convertHelper(cur->right, pre);
}
};
非遞歸解法
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
#include<iostream>
#include<stack>
using namespace std;
class Solution {
public:
TreeNode* Convert(TreeNode* pRootOfTree) {
if (!pRootOfTree) {
return nullptr;
}
TreeNode DummyHead(-1);
TreeNode *dp = &DummyHead;
TreeNode *p = pRootOfTree;
stack<TreeNode*> st;
while (p || !st.empty()) {
if (p) {
st.push(p);
p = p->left;
} else {
p = st.top();
st.pop();
dp->right = p;
p->left = dp;
dp = p;
p = p->right;
}
}
DummyHead.right->left = nullptr;
return DummyHead.right;
}
};
他人秋招三面通過面經
用了同學的白金內推碼,所以直接進入了面試,全程都在寫題!機器學習的問題非常少!
一面:
1、介紹項目
2、強化學習PG的推導
3、強化學習DQN,DDQN,AC,DDPG的區別
4、n個[0,n)的數,求每個數的出現次數(不能開辟額外空間)
5、K個有序數組,找一個長度最小的區間,在這個區間里至少包含每個數組各一個數。
分析:初始化帶下為K的最小堆,K個數字是每個數組中的最小值,設置變量max記錄k個數字中的最大值,刪除堆頂元素,將原堆頂元素對應的數組中下一個元素加入到堆中,調整堆,並且記錄當前區間范圍為(max-min),重復執行直到某個數組所有值都被刪除。
二面
1、介紹DQN的項目
2、數組的全排列(空間復雜度O(1))
數組中有重復元素,所以我們需要一個Set保存已經出現過的排列。因此我先寫了一個回溯的方法,可是空間復雜度比較高,面試官說能不能用O(1)的空間復雜度,全排列直接print出來就行。即我們不需要保存已經出現過什么排列。這需要對數組先進性排序。
3、兩堆鈔票,盡可能均分(利用背包問題的思想)
想了半天,寫出來一個深度優先搜索的算法。面試官提示我可以考慮從背包問題的角度出發,但最后也沒想出來。
三面:
1、無向無環圖中,最短路徑的最大值(O(n^3)的解法)
這里考察的其實就是Floyd算法。哎,只可惜自己當時沒有復習圖的相關算法,完全不會寫呀。
算法思想原理:Floyd算法是一個經典的動態規划算法。用通俗的語言來描述的話,首先我們的目標是尋找從點i到點j的最短路徑。
從任意節點i到任意節點j的最短路徑不外乎2種可能,1是直接從i到j,2是從i經過若干個節點k到j。所以,我們假設Dis(i,j)為節點u到節點v的最短路徑的距離,對於每一個節點k,我們檢查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,證明從i到k再到j的路徑比i直接到j的路徑短,我們便設置Dis(i,j) = Dis(i,k) + Dis(k,j),這樣一來,當我們遍歷完所有節點k,Dis(i,j)中記錄的便是i到j的最短路徑的距離。
2、LSTM的公式
3、RNN為什么出現梯度消失
4、BPTT的推導。