diff --git a/Week_01/README.md b/Week_01/README.md index 50de3041..fa8d8072 100644 --- a/Week_01/README.md +++ b/Week_01/README.md @@ -1 +1,10 @@ -学习笔记 \ No newline at end of file +学习笔记 + +* 五毒神掌(限时5分钟、临摹、理解、模仿、次日写、看高手多题解、通过是开始,看高票代码、高质量题解) + +进步点: + 多个算法已经可以快速准确写出来 + +缺点: + 国际站题解看的较少,需要有意识增加 + diff --git a/Week_01/main.cpp b/Week_01/main.cpp new file mode 100644 index 00000000..81047d0d --- /dev/null +++ b/Week_01/main.cpp @@ -0,0 +1,28 @@ +// 5、合并两个有序链表(亚马逊、字节跳动在半年内面试常考) +ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { + if (l1 == nullptr) return l2; + if (l2 == nullptr) return l1; + + if (l1->val < l2->val) { + l1->next = mergeTwoLists(l1->next, l2); + return l1; + } else { + l2->next = mergeTwoLists(l1, l2->next); + return l2; + } +} + + +// 9、加一(谷歌、字节跳动、Facebook 在半年内面试中考过) +vector plusOne(vector& digits) { + int left = 1; + for (int i = digits.size() - 1; i >= 0; --i) { + int sums = digits[i] + left; + left = sums / 10; + int num = sums - 10 * left; + digits[i] = num; + } + + if (left > 0) digits.insert(digits.begin(), left); + return digits; +} \ No newline at end of file diff --git a/Week_02/README.md b/Week_02/README.md index 50de3041..0920ca9a 100644 --- a/Week_02/README.md +++ b/Week_02/README.md @@ -1 +1,5 @@ -学习笔记 \ No newline at end of file +学习笔记 + +由于本周本人一直处于中耳炎的折磨当中,没有及时跟上班级进度,又不想拖累班级,因此本次作业仅仅是为了完成任务。等病好了,一定重复补上,实在抱歉。 + + diff --git a/Week_02/main.cpp b/Week_02/main.cpp new file mode 100644 index 00000000..406e2838 --- /dev/null +++ b/Week_02/main.cpp @@ -0,0 +1,38 @@ +// 前序排列 +class Solution { +public: + vector res; + + void _preorder(Node *root) { + if (root == nullptr) return; + res.push_back(root->val); + + for(int i = 0; i< root->children.size(); i++) { + _preorder(root->children[i]); + } + } + + vector preorder(Node* root) { + _preorder(root); + return res; + } +}; + +// 中序排列 +class Solution { +public: + vector res; + void inorder(TreeNode* root) { + if (root == nullptr) return; + inorder(root->left); + res.push_back(root->val); + inorder(root->right); + } + + vector inorderTraversal(TreeNode* root) { + inorder(root); + return res; + } +}; + + diff --git a/Week_03/README.md b/Week_03/README.md index 50de3041..7de8df63 100644 --- a/Week_03/README.md +++ b/Week_03/README.md @@ -1 +1,53 @@ -学习笔记 \ No newline at end of file +学习笔记 + +树的面试题解法一般都是递归。 +1、节点的定义 +2、重复性(自相似性) + +递归就是循环,通过函数体来进行的循环。 + +递归代码模板: +``` +def recursion(level,param1,param2,...): + # recursion terminator 递归终结条件 + if level > MAX_LEVEL: + process_result + return + + # process logic in current level 处理当前层逻辑 + process(level, data ...) + + # drill down 下探到下一层 + self.recursion(level + 1, p1, ...) + + # reserse the current level status if needed 清理当前层 +```$$ + +思维要点 + 1、不要人肉进行递归 (最大误区) + 2、找到最近最简方法,将其拆解成可重复解决的问题(重复子问题) + 3、数学归纳法思维 + +分治 + 就是一个递归 + 找重复性及分解问题,和组合每个子问题的结果 + +回溯 + 不断试错 + 平行+嵌套 分别对应循环+递归 + + 回溯模板: +``` + void backtracking(参数) { + if (终止条件) { + 存放结果 + return; + } + + for (选择: 本层集合中元素(树中节点孩子的数量就是集合的大小)) { + 处理节点; + backtracking(路径,选择列表); // 递归 + 回溯,撤销处理结果 + } + } +``` \ No newline at end of file diff --git a/Week_03/solutions.cpp b/Week_03/solutions.cpp new file mode 100644 index 00000000..0c3e1267 --- /dev/null +++ b/Week_03/solutions.cpp @@ -0,0 +1,127 @@ +// 二叉树的最近公共祖先 +class Solution { +public: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + // terminal + if (!root || !p || !q || p == root || q == root) return root; + + // drill down + TreeNode* leftTree = lowestCommonAncestor(root->left, p, q); + TreeNode* rightTree = lowestCommonAncestor(root->right, p, q); + + // process logic in current level + if (!leftTree && !rightTree) return NULL; + if (leftTree && rightTree) return root; + if (!leftTree && rightTree) return rightTree; + if (leftTree && !rightTree) return leftTree; + + return NULL; + } +}; + +// 组合 +class Solution { +private: + void _backtracking(int n, int k, int startIndex, vector>& result, vector& path) { + if (path.size() == k) { + result.push_back(path); + return; + } + + for (int i = startIndex; i <= n - (k - path.size()) + 1; ++i) { + path.push_back(i); // 处理节点 + _backtracking(n, k, i + 1, result, path); + path.pop_back(); // 回溯,撤销处理的节点 + } + } + +public: + vector> combine(int n, int k) { + vector> result; + vector path; + _backtracking(n, k, 1, result, path); + return result; + } +}; + +// 从前序与中序遍历序列构造二叉树 +class Solution { +private: + unordered_map index; + TreeNode* myBuildTree(const vector& preorder, const vector& inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right) { + if (preorder_left > preorder_right) { + return nullptr; + } + + int preorder_root = preorder_left; + int inorder_root = index[preorder[preorder_root]]; + + TreeNode* root = new TreeNode(preorder[preorder_root]); + int size_left_subtree = inorder_root - inorder_left; + root->left = myBuildTree(preorder, inorder, preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1); + root->right = myBuildTree(preorder, inorder, preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right); + return root; + } +public: + TreeNode* buildTree(vector& preorder, vector& inorder) { + int n = preorder.size(); + for (int i = 0; i < n; ++i) { + index[inorder[i]] = i; + } + + return myBuildTree(preorder, inorder, 0, n - 1, 0, n - 1); + } +}; + +// 全排列 +class Solution { +private: + void backtracking(vector>& res, vector& output, int first, int len) { + if (first == len) { + res.emplace_back(output); + return; + } + + for (int i = first; i < len; ++i) { + swap(output[i],output[first]); + backtracking(res, output, first + 1, len); + swap(output[i], output[first]); + } + } +public: + vector> permute(vector& nums) { + vector> res; + backtracking(res, nums, 0, nums.size()); + return res; + } +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Week_04/README.md b/Week_04/README.md index 50de3041..d445bf74 100644 --- a/Week_04/README.md +++ b/Week_04/README.md @@ -1 +1,17 @@ -学习笔记 \ No newline at end of file +学习笔记 + +贪心法可以解决一些最优化问题,如: 求图中的最小生成树、求哈夫曼编码等 +一旦一个问题可以通过贪心法来解决,那么贪心法一般是解决这个问题的最好办法。由于贪心法的高效性及其所求得的答案 +比较接近最优结果,贪心法也可以用作辅助算法或者直接解决一些要求结果不特别精确的问题。 + +二分查找的前提 +1、目标函数单调性(单调递增或递减) +2、存在上下界(bounded) +3、能够通过索引访问(index accessable) + +五毒神掌 +四步做题法: +1、审题:细节、边界条件、输入输出的范围 +2、所有的解法都思考一遍,时间/空间复杂度等,得出最优解法 +3、写代码 +4、测试样例、 \ No newline at end of file diff --git a/Week_04/solution b/Week_04/solution new file mode 100644 index 00000000..13bb7b08 --- /dev/null +++ b/Week_04/solution @@ -0,0 +1,69 @@ +1、柠檬找零 +class Solution { +public: + bool lemonadeChange(vector& bills) { + int five = 0; + int ten = 0; + for (int i = 0; i < bills.size(); ++i) { + int price = bills[i]; + if (price == 5) { + five++; + } else if (price == 10) { + five--; + ten++; + } else if (price == 20) { + if (ten > 0) { + ten--; + five--; + } else { + five -= 3; + } + } + + if (five < 0 || ten < 0) return false; + } + + return true; + } +}; + +2、买卖股票的最佳时机 II +class Solution { +public: + int maxProfit(vector& prices) { + // dp[i][1] 第i天持有的最多现金 + // dp[i][0] 第i天持有股票后的最多现金 + int n = prices.size(); + vector> dp(n, vector(2, 0)); + dp[0][0] -= prices[0]; // 持股票 + + for (int i = 1; i < n; ++i) { + // 第i天持股票所剩最多现金 = max(第i - 1天持有股票所剩现金,第i-1天持现金 - 买第i天的股票) + dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]); + dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i]); + } + + return max(dp[n - 1][0], dp[n - 1][1]); + } +}; + +3、分发饼干 +class Solution { +public: + int findContentChildren(vector& g, vector& s) { + sort(g.begin(), g.end()); + sort(s.begin(), s.end()); + int count = 0; + int gSize = g.size(); + int sSize = s.size(); + int j = 0; // 指向g + for (int i = 0; i < sSize && j < gSize; ++i) { + if (g[j] <= s[i]) { + count++; + j++; + } + } + + return count; + } +}; \ No newline at end of file