├── .clang-format ├── .gitignore ├── .vscode ├── launch.json ├── lc.code-snippets ├── settings.json └── tasks.json ├── Array ├── 121.cc ├── 153.cc ├── 162.cc ├── 215.cc ├── 33.cc ├── 34.cc ├── 4.cc ├── 435.cc ├── 46.cc ├── 48.cc ├── 498.cc ├── 54.cc ├── 56.cc ├── 57.cc ├── 73.cc └── 77.cc ├── DP ├── 1035.cc ├── 1143.cc ├── 115.cc ├── 120.cc ├── 122.cc ├── 1277.cc ├── 152.cc ├── 198.cc ├── 213.cc ├── 221.cc ├── 300.cc ├── 32.cc ├── 322.cc ├── 343.cc ├── 343.py ├── 392.cc ├── 42.cc ├── 516.cc ├── 518.cc ├── 53.cc ├── 583.cc ├── 62.cc ├── 62.py ├── 63.cc ├── 64.cc ├── 64.py ├── 647.cc ├── 70.cc ├── 718.cc ├── 746.cc ├── 790.cc ├── 931.cc ├── 97.cc ├── 980.cc └── kama46.cc ├── DataStructure ├── graph.cc ├── link_list.cc └── stack.cc ├── DoublePointer ├── 11.cc ├── 1100.cc ├── 15.cc ├── 159.cc ├── 3.cc ├── 340.cc ├── 392.cc └── 88.cc ├── Geometry ├── point_prejection.cc └── point_triangle.cc ├── Graph ├── 103.cc ├── 200.cc ├── 2290.cc ├── 2685.cc ├── 417.cc ├── 695.cc ├── 797.cc ├── 815.cc ├── 827.cc └── all_possible_paths_with_weight.cc ├── Greedy ├── 45.cc ├── 55.cc └── 860.cc ├── HashTable ├── 1.cc └── 128.cc ├── LinkList ├── 141.cc ├── 147.cc ├── 148.cc ├── 19.cc ├── 206.cc ├── 23.cc ├── 328.cc ├── 92.cc └── 92.reverse_link_list2.cc ├── ML ├── clip.py ├── conv.py ├── deformable_conv.py ├── focal_loss.py ├── iou.py ├── mat_mul.py ├── multi_atten.py ├── nms.py ├── self_attention.py ├── transformer_layer.py └── vit.py ├── NumericalComputation ├── 50.cc ├── 69.cc ├── determinant.cc ├── eigen.cc ├── eigen │ ├── CMakeLists.txt │ └── test.cc ├── least_square.cc ├── lnx+x^2.cc └── matrix_multiply.cc ├── OS ├── mt_shared_ptr.cc └── pipe.cc ├── Others ├── 86.cc ├── bin_search.cc ├── class_inherit.cc ├── shared_ptr.cc ├── singleton.cc ├── unique_ptr.cc └── vector.cc ├── README.md ├── SortSearch └── quick_sort.cc ├── StackQueue ├── 150.cc ├── 20.cc ├── 239.cc └── prefix_expression.py ├── String └── 5.cc ├── Tree ├── 102.cc ├── 104.cc ├── 105.cc ├── 226.cc ├── 236.cc ├── 654.cc ├── 98.cc ├── cow_group.cc └── stand_traverse.cc ├── clean.py ├── count.sh ├── header.hpp ├── main.cc └── main.py /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Microsoft 2 | ColumnLimit: 100 3 | IndentWidth: 4 4 | 5 | AllowShortLoopsOnASingleLine: false 6 | AllowShortIfStatementsOnASingleLine: true 7 | AllowShortBlocksOnASingleLine: true 8 | AllowShortFunctionsOnASingleLine: false 9 | 10 | Language: Cpp 11 | AccessModifierOffset: -4 12 | NamespaceIndentation: None 13 | IndentAccessModifiers: false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .stfolder/ 3 | **sync-conflict** 4 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "type": "lldb", 5 | "request": "launch", 6 | "name": "build&debug", 7 | "program": "${fileDirname}/${fileBasenameNoExtension}", 8 | "args": [], 9 | "cwd": "${fileDirname}", 10 | "preLaunchTask": "C/C++: clang++ build active file", 11 | }, 12 | ] 13 | } -------------------------------------------------------------------------------- /.vscode/lc.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "LeetCode Solution Template": { 3 | "prefix": "lcsol", 4 | "body": [ 5 | "/**", 6 | " * @name ${1}", 7 | " * @details ${2}", 8 | " * @url ${3}", 9 | " * @idea ${4}", 10 | " * @note ${5}", 11 | " */", 12 | "#include \"../header.hpp\"", 13 | "", 14 | "class Solution", 15 | "{", 16 | "public:", 17 | " ${6:int functionName()}", 18 | " {", 19 | " return 0;", 20 | " }", 21 | "};", 22 | "", 23 | "int main(int argc, char const *argv[])", 24 | "{", 25 | " Solution s;", 26 | " return 0;", 27 | "}" 28 | ], 29 | "description": "LeetCode Solution Template" 30 | }, 31 | "Problem Checkbox": { 32 | "prefix": "probbox", 33 | "body": ["- [ ] [${1}](${2})."] 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "vector": "cpp", 4 | "__hash_table": "cpp", 5 | "__split_buffer": "cpp", 6 | "array": "cpp", 7 | "bitset": "cpp", 8 | "deque": "cpp", 9 | "initializer_list": "cpp", 10 | "queue": "cpp", 11 | "stack": "cpp", 12 | "string": "cpp", 13 | "string_view": "cpp", 14 | "unordered_map": "cpp", 15 | "ostream": "cpp", 16 | "__bit_reference": "cpp", 17 | "__config": "cpp", 18 | "__debug": "cpp", 19 | "__errc": "cpp", 20 | "__locale": "cpp", 21 | "__mutex_base": "cpp", 22 | "__node_handle": "cpp", 23 | "__threading_support": "cpp", 24 | "__verbose_abort": "cpp", 25 | "atomic": "cpp", 26 | "cctype": "cpp", 27 | "charconv": "cpp", 28 | "clocale": "cpp", 29 | "cmath": "cpp", 30 | "complex": "cpp", 31 | "cstdarg": "cpp", 32 | "cstddef": "cpp", 33 | "cstdint": "cpp", 34 | "cstdio": "cpp", 35 | "cstdlib": "cpp", 36 | "cstring": "cpp", 37 | "ctime": "cpp", 38 | "cwchar": "cpp", 39 | "cwctype": "cpp", 40 | "exception": "cpp", 41 | "ios": "cpp", 42 | "iosfwd": "cpp", 43 | "iostream": "cpp", 44 | "istream": "cpp", 45 | "limits": "cpp", 46 | "locale": "cpp", 47 | "mutex": "cpp", 48 | "new": "cpp", 49 | "optional": "cpp", 50 | "ratio": "cpp", 51 | "sstream": "cpp", 52 | "stdexcept": "cpp", 53 | "streambuf": "cpp", 54 | "system_error": "cpp", 55 | "tuple": "cpp", 56 | "typeinfo": "cpp", 57 | "variant": "cpp", 58 | "algorithm": "cpp", 59 | "unordered_set": "cpp", 60 | "set": "cpp", 61 | "__tree": "cpp", 62 | "execution": "cpp" 63 | }, 64 | "workbench.colorCustomizations": { 65 | "activityBar.background": "#78C3A7", 66 | "titleBar.activeBackground": "#8DCCB5", 67 | "titleBar.activeForeground": "#0D1C16" 68 | }, 69 | "[markdown]": { 70 | "editor.quickSuggestions": { 71 | "other": true, 72 | "comments": true, 73 | "strings": true 74 | }, 75 | "editor.acceptSuggestionOnEnter": "on" 76 | } 77 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "type": "cppbuild", 5 | "label": "C/C++: clang++ build active file", 6 | "command": "/usr/bin/clang++", 7 | "args": [ 8 | "-fcolor-diagnostics", 9 | "-fansi-escape-codes", 10 | "-g", 11 | "${file}", 12 | "-o", 13 | "${fileDirname}/${fileBasenameNoExtension}" 14 | ], 15 | "options": { 16 | "cwd": "${fileDirname}" 17 | }, 18 | "problemMatcher": [ 19 | "$gcc" 20 | ], 21 | "group": { 22 | "kind": "build", 23 | "isDefault": true 24 | }, 25 | "detail": "compiler: /usr/bin/clang++" 26 | } 27 | ] 28 | } -------------------------------------------------------------------------------- /Array/121.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 121.买卖股票的最佳时机 3 | * @details 4 | * @url https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/description/ 5 | * @idea 一次遍历,找最小的值,然后比较当前值和最小值的差,得到最大值 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int maxProfit(vector &prices) 14 | { 15 | int n = prices.size(); 16 | int min_profit = prices[0]; 17 | int max_diff = 0; 18 | for (int i = 0; i < n; i++) 19 | { 20 | min_profit = min(min_profit, prices[i]); 21 | max_diff = max(max_diff, prices[i] - min_profit); 22 | } 23 | return max_diff; 24 | } 25 | }; 26 | 27 | int main(int argc, char const *argv[]) 28 | { 29 | Solution s; 30 | vector ar = {7, 1, 5, 3, 6, 4}; 31 | int profit = s.maxProfit(ar); 32 | cout << profit; 33 | } -------------------------------------------------------------------------------- /Array/153.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 153[M].寻找旋转排序数组中的最小值 3 | * @details 4 | * @url https://leetcode.cn/problems/find-minimum-in-rotated-sorted-array/ 5 | * @idea 二分查找,可以画图判断pivot和边界的递推关系 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int findMin(vector &nums) 14 | { 15 | int n = nums.size(); 16 | int left = 0, right = n - 1; 17 | int mid; 18 | while (left < right) 19 | { 20 | mid = (left + right) / 2; 21 | if (nums[mid] < nums[right]) { right = mid; } 22 | else if (nums[mid] > nums[right]) { left = mid + 1; } 23 | } 24 | return nums[left]; 25 | } 26 | }; 27 | 28 | int main(int argc, char const *argv[]) 29 | { 30 | Solution s; 31 | return 0; 32 | } -------------------------------------------------------------------------------- /Array/162.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 162.寻找峰值 3 | * @details 4 | * @url https://leetcode.cn/problems/find-peak-element/description/ 5 | * @idea 根据单调性二分查找迭代搜索区间 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int findPeakElement(vector &nums) 14 | { 15 | int n = nums.size(); 16 | int left = 0, right = n - 1; 17 | while (left < right) 18 | { 19 | int mid = (left + right) / 2; 20 | if (nums[mid] < nums[mid + 1]) 21 | { 22 | left = mid + 1; // 峰值在右边 23 | } 24 | else 25 | { 26 | right = mid; // 峰值在左边或者mid就是峰值 27 | } 28 | } 29 | return left; 30 | } 31 | }; 32 | 33 | int main(int argc, char const *argv[]) 34 | { 35 | Solution s; 36 | vector ar = {1, 2, 3, 1}; 37 | int idx = s.findPeakElement(ar); 38 | cout << idx; 39 | return 0; 40 | } -------------------------------------------------------------------------------- /Array/215.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 215[M].数组中的第 K 个最大元素(top k 3 | * @details 4 | * @url https://leetcode.cn/problems/kth-largest-element-in-an-array/description/ 5 | * @idea 桶排序或者选择性快速排序:只关心pivot,如果pivot刚好就是k就返回, 6 | * 否则根据pivot和n-k的关系决定下一个子数组的范围 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | // 极端案例会超时 12 | class Solution1 13 | { 14 | public: 15 | int findKthLargest(std::vector &nums, int k) 16 | { 17 | return quickselect(nums, 0, nums.size() - 1, k); 18 | } 19 | 20 | private: 21 | int quickselect(std::vector &nums, int left, int right, int k) 22 | { 23 | // 使用快速排序的划分方式 24 | int pivotIndex = partition(nums, left, right); 25 | 26 | // 找到第 k 大的元素 27 | if (pivotIndex == nums.size() - k) { return nums[pivotIndex]; } 28 | else if (pivotIndex > nums.size() - k) 29 | { 30 | return quickselect(nums, left, pivotIndex - 1, k); 31 | } 32 | else { return quickselect(nums, pivotIndex + 1, right, k); } 33 | } 34 | 35 | int partition(std::vector &nums, int left, int right) 36 | { 37 | // 使用最左边的元素作为pivot 38 | int pivot = nums[left]; 39 | int i = left + 1; 40 | int j = right; 41 | 42 | while (true) 43 | { 44 | while (i <= j && nums[i] <= pivot) 45 | i++; 46 | while (i <= j && nums[j] > pivot) 47 | j--; 48 | if (i >= j) break; 49 | std::swap(nums[i], nums[j]); 50 | } 51 | std::swap(nums[left], nums[j]); 52 | 53 | return j; 54 | } 55 | }; 56 | 57 | // 官方题解,省略了partition函数,加速递归 58 | class Solution 59 | { 60 | public: 61 | int quickselect(vector &nums, int l, int r, int k) 62 | { 63 | if (l == r) return nums[k]; 64 | int pivot = nums[l], i = l - 1, j = r + 1; 65 | while (i <= j) 66 | { 67 | while (i <= j && nums[i] < pivot) 68 | i++; 69 | 70 | while (i <= j && nums[j] > pivot) 71 | j--; 72 | 73 | if (i <= j) 74 | { 75 | std::swap(nums[i], nums[j]); 76 | i++; 77 | j--; 78 | } 79 | } 80 | if (k <= j) 81 | return quickselect(nums, l, j, k); 82 | else 83 | return quickselect(nums, j + 1, r, k); 84 | } 85 | 86 | int findKthLargest(vector &nums, int k) 87 | { 88 | int n = nums.size(); 89 | return quickselect(nums, 0, n - 1, n - k); 90 | } 91 | }; 92 | 93 | int main(int argc, char const *argv[]) 94 | { 95 | Solution s; 96 | vector vec = {3, 2, 3, 1, 2, 4, 5, 5, 6}; 97 | int res = s.findKthLargest(vec, 4); 98 | cout << res; 99 | return 0; 100 | } -------------------------------------------------------------------------------- /Array/33.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 33[M].搜索旋转排列数组 3 | * @details 4 | * @url https://leetcode.cn/problems/search-in-rotated-sorted-array/description/ 5 | * @idea 6 | * 选择性二分查找,根据mid所在位置判断左右两边哪边是有序的,并判断target值和左右区间边界值的大小来更新二分查找的边界 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | public: 14 | int search(vector &nums, int target) 15 | { 16 | int n = nums.size(); 17 | int l = 0, r = n - 1; 18 | 19 | if (n == 1) return nums[0] == target ? 0 : -1; 20 | 21 | while (l <= r) 22 | { 23 | int mid = (l + r) / 2; 24 | if (nums[mid] == target) return mid; 25 | if (nums[mid] >= nums[0]) // 左半边是有序的 26 | { 27 | // target就在有序的左半边 28 | if (target < nums[mid] && target >= nums[0]) // NOTE: 所有和target和nums[mid]的比较都不带等号 29 | { 30 | r = mid - 1; // 在有序区间内二分 31 | } 32 | else 33 | { 34 | l = mid + 1; // 无法二分,在右区间顺序查找 35 | } 36 | } 37 | else // 右半边是有序的 38 | { 39 | if (target > nums[mid] && target <= nums[n - 1]) { l = mid + 1; } 40 | else { r = mid - 1; } 41 | } 42 | } 43 | return -1; 44 | } 45 | }; 46 | 47 | int main(int argc, char const *argv[]) 48 | { 49 | Solution s; 50 | return 0; 51 | } -------------------------------------------------------------------------------- /Array/34.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 34[M]. 在排序数组中查找元素的第一个和最后一个位置 3 | * @details 4 | * @url https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/ 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int functionName() 14 | { 15 | return 0; 16 | } 17 | }; 18 | 19 | int main(int argc, char const *argv[]) 20 | { 21 | Solution s; 22 | return 0; 23 | } -------------------------------------------------------------------------------- /Array/4.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 4[H].寻找两个正序数组的中位数 3 | * @details 4 | * @url https://leetcode.cn/problems/median-of-two-sorted-arrays/ 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int functionName() 14 | { 15 | return 0; 16 | } 17 | }; 18 | 19 | int main(int argc, char const *argv[]) 20 | { 21 | Solution s; 22 | return 0; 23 | } -------------------------------------------------------------------------------- /Array/435.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 435[M].无重叠区间 3 | * @details 4 | * @url https://leetcode.cn/problems/non-overlapping-intervals 5 | * @idea 本质和300.最长上升子序列一样,动态规划,等价于选择数量最多的互不重叠的区间, 6 | * dp[i]表示以第i个区间结束不重叠的最大区间数量 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | // 这种方法会超时 12 | class Solution 13 | { 14 | public: 15 | int eraseOverlapIntervals(vector> &intervals) 16 | { 17 | int n = intervals.size(); 18 | if (!n) return 0; 19 | sort(intervals.begin(), intervals.end(), 20 | [](vector &u, vector &v) { return u[0] < v[0]; }); 21 | vector dp(n, 1); 22 | for (int i = 1; i < n; i++) 23 | { 24 | for (int j = 0; j < i; j++) 25 | { 26 | if (intervals[j][1] <= intervals[i][0]) { dp[i] = max(dp[i], dp[j] + 1); } 27 | } 28 | } 29 | return n - *max_element(dp.begin(), dp.end()); 30 | } 31 | }; 32 | int main(int argc, char const *argv[]) 33 | { 34 | Solution s; 35 | return 0; 36 | } -------------------------------------------------------------------------------- /Array/46.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 46[M].全排列 3 | * @details 4 | * @url https://leetcode.cn/problems/permutations/description/ 5 | * @idea 递归回溯, 直接操作原数组,分成左右两半,遍历每一位数字,每次把当前数字交换到idx处,相当于固定开头,不重复地组合剩余的数字 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | vector> permute(vector &nums) 14 | { 15 | int n = nums.size(); 16 | vector> res; 17 | backtrace(nums, res, 0, n); 18 | return res; 19 | } 20 | 21 | void backtrace(vector &nums, vector> &res, int idx, int n) 22 | { 23 | if (idx == n) 24 | { 25 | res.push_back(nums); 26 | return; 27 | } 28 | for (int i = idx; i < n; i++) 29 | { 30 | std::swap(nums[i], nums[idx]); 31 | backtrace(nums, res, idx + 1, n); 32 | std::swap(nums[i], nums[idx]); 33 | } 34 | } 35 | }; 36 | 37 | int main(int argc, char const *argv[]) 38 | { 39 | Solution s; 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /Array/48.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 48.旋转图像 3 | * @details 顺时针旋转二维数组 4 | * @url 5 | * @idea 6 | * 1.用辅助数组,旋转后第i行第j列对应新数组中的倒数第i行和第j列; 7 | * 2.原地旋转,利用temp变量保存中间结果,比较复杂不考虑; 8 | * 3.翻转代替旋转,先水平线翻转,再对角线翻转即可,推荐使用 9 | * @note 10 | */ 11 | #include "../header.hpp" 12 | 13 | class Solution 14 | { 15 | public: 16 | void rotate(vector> &matrix) 17 | { 18 | int n = matrix.size(); 19 | // horizontal flip 20 | for (int i = 0; i < n / 2; i++) // NOTE: must be n/2 21 | { 22 | for (int j = 0; j < n; j++) { swap(matrix[i][j], matrix[n - i - 1][j]); } 23 | } 24 | 25 | // diagonal flip 26 | for (int i = 0; i < n; i++) 27 | { 28 | for (int j = 0; j < i; j++) { swap(matrix[i][j], matrix[j][i]); } 29 | } 30 | } 31 | }; 32 | 33 | int main() 34 | { 35 | Solution solution; 36 | 37 | // Test case 1 38 | vector> matrix1 = { 39 | {1, 2, 3}, 40 | {4, 5, 6}, 41 | {7, 8, 9}, 42 | }; 43 | solution.rotate(matrix1); 44 | cout << "Test case 1 result:" << endl; 45 | PrintMatrix(matrix1); 46 | 47 | // Test case 2 48 | vector> matrix2 = { 49 | {5, 1, 9, 11}, 50 | {2, 4, 8, 10}, 51 | {13, 3, 6, 7}, 52 | {15, 14, 12, 16}, 53 | }; 54 | solution.rotate(matrix2); 55 | cout << "Test case 2 result:" << endl; 56 | PrintMatrix(matrix2); 57 | 58 | // Test case 3 59 | vector> matrix3 = { 60 | {1, 2}, 61 | {3, 4}, 62 | }; 63 | solution.rotate(matrix3); 64 | cout << "Test case 3 result:" << endl; 65 | PrintMatrix(matrix3); 66 | 67 | // Test case 4 68 | vector> matrix4 = {{1}}; 69 | solution.rotate(matrix4); 70 | cout << "Test case 4 result:" << endl; 71 | PrintMatrix(matrix4); 72 | 73 | // Test case 5 74 | vector> matrix5 = { 75 | {1, 2, 3, 4}, 76 | {5, 6, 7, 8}, 77 | {9, 10, 11, 12}, 78 | {13, 14, 15, 16}, 79 | }; 80 | solution.rotate(matrix5); 81 | cout << "Test case 5 result:" << endl; 82 | PrintMatrix(matrix5); 83 | 84 | return 0; 85 | } -------------------------------------------------------------------------------- /Array/498.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 498[M]. 对角线遍历 3 | * @details 4 | * @url 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int functionName() 14 | { 15 | return 0; 16 | } 17 | }; 18 | 19 | int main(int argc, char const *argv[]) 20 | { 21 | Solution s; 22 | return 0; 23 | } -------------------------------------------------------------------------------- /Array/54.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 54.螺旋数组 3 | * @details 4 | * @url https://leetcode.cn/problems/spiral-matrix/description/ 5 | * @idea 用同尺寸2d数组标记已访问元素,用方向数组调整遍历方向. 6 | * 每次更新下标时先判断新下标的范围和数字,决定是否要更新迭代方向 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | private: 14 | public: 15 | /* 模拟法 */ 16 | vector spiralOrder(vector> &matrix) 17 | { 18 | int height = matrix.size(); 19 | int width = matrix[0].size(); 20 | int total = height * width; 21 | const int dirs[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; 22 | 23 | // visited flag matrix 24 | vector> visited(height, vector(width, false)); 25 | vector result; 26 | 27 | int row_idx = 0, col_idx = 0, dir_idx = 0; 28 | for (int i = 0; i < total; i++) 29 | { 30 | visited[row_idx][col_idx] = true; 31 | result.push_back(matrix[row_idx][col_idx]); 32 | int next_row = row_idx + dirs[dir_idx][0], next_col = col_idx + dirs[dir_idx][1]; 33 | if (next_row > height - 1 || next_row < 0 || next_col > width - 1 || next_col < 0 || 34 | visited[next_row][next_col]) 35 | { 36 | dir_idx = (dir_idx + 1) % 4; 37 | } 38 | row_idx += dirs[dir_idx][0]; 39 | col_idx += dirs[dir_idx][1]; 40 | } 41 | return result; 42 | } 43 | 44 | /* 边界裁剪法 */ 45 | vector spiralOrder2(vector> &matrix) 46 | { 47 | int height = matrix.size(); 48 | int width = matrix[0].size(); 49 | int total = height * width; 50 | vector result; 51 | 52 | int row_low = 0, col_low = 0, row_high = height - 1, col_high = width - 1; 53 | while (true) 54 | { 55 | for (int i = col_low; i <= col_high; i++) { result.push_back(matrix[row_low][i]); } 56 | if (++row_low > row_high) { break; } 57 | for (int i = row_low; i <= row_high; i++) { result.push_back(matrix[i][col_high]); } 58 | if (--col_high < col_low) { break; } 59 | for (int i = col_high; i >= col_low; i--) { result.push_back(matrix[row_high][i]); } 60 | if (--row_high < row_low) { break; } 61 | for (int i = row_high; i >= row_low; i--) { result.push_back(matrix[i][col_low]); } 62 | if (++col_low > col_high) { break; } 63 | } 64 | return result; 65 | } 66 | }; 67 | 68 | void testSpiralOrder() 69 | { 70 | Solution solution; 71 | 72 | vector> matrix1 = { 73 | {1, 2, 3}, 74 | {4, 5, 6}, 75 | {7, 8, 9}, 76 | }; 77 | // vector result1 = solution.spiralOrder(matrix1); 78 | vector result1 = solution.spiralOrder2(matrix1); 79 | for (int num : result1) { cout << num << " "; } 80 | cout << endl; 81 | 82 | vector> matrix2 = { 83 | {1, 2, 3, 4}, 84 | {5, 6, 7, 8}, 85 | {9, 10, 11, 12}, 86 | }; 87 | // vector result2 = solution.spiralOrder(matrix2); 88 | vector result2 = solution.spiralOrder2(matrix2); 89 | for (int num : result2) { cout << num << " "; } 90 | cout << endl; 91 | } 92 | 93 | int main() 94 | { 95 | testSpiralOrder(); 96 | return 0; 97 | } -------------------------------------------------------------------------------- /Array/56.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 56. 合并区间 3 | * @details 4 | * @url https://leetcode.cn/problems/merge-intervals/ 5 | * @idea 按照左端点排序,然后遍历 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | vector> merge(vector> &intervals) 14 | { 15 | if (intervals.size() == 0) return {}; 16 | vector> merged; 17 | sort(intervals.begin(), intervals.end()); 18 | for (int i = 0; i < intervals.size(); i++) 19 | { 20 | int l = intervals[i][0]; 21 | int r = intervals[i][1]; 22 | if (merged.size() == 0 || l > merged.back()[1]) { merged.push_back({l, r}); } 23 | else 24 | { 25 | merged.back()[1] = max(merged.back()[1], r); // NOTE: remember to use max() 26 | } 27 | } 28 | return merged; 29 | } 30 | }; 31 | 32 | int main(int argc, char const *argv[]) { Solution s; } -------------------------------------------------------------------------------- /Array/57.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 57[M].插入区间 3 | * @details 4 | * @url https://leetcode.cn/problems/insert-interval/ 5 | * @idea 不断取区间和给定区间的并集,直到新区间和原区间断开(也就是right < li)的时候将新区间插入 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | vector> insert(vector> &intervals, vector &newInterval) 14 | { 15 | int left = newInterval[0], right = newInterval[1]; 16 | vector> ans; 17 | bool added = false; 18 | for (auto &interval : intervals) 19 | { 20 | if (interval[0] > right) 21 | { 22 | if (!added) 23 | { 24 | ans.push_back({left, right}); 25 | added = true; 26 | } 27 | ans.push_back(interval); 28 | } 29 | else if (interval[1] < left) { ans.push_back(interval); } 30 | else 31 | { 32 | left = min(left, interval[0]); 33 | right = max(right, interval[1]); 34 | } 35 | } 36 | if (!added) { ans.push_back({left, right}); } 37 | return ans; 38 | } 39 | }; 40 | int main(int argc, char const *argv[]) 41 | { 42 | Solution s; 43 | return 0; 44 | } -------------------------------------------------------------------------------- /Array/73.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 73[M].矩阵置零 3 | * @details 4 | * @url https://leetcode.cn/problems/set-matrix-zeroes/ 5 | * @idea 用额外的两个 vector作为行列标记,每遍历到0就标记,再遍历一次数组置零。 6 | * (建议)可以只用第一行和第一列标记0,但需要额外的两个变量标记第一行第一列本身是否包含0。 7 | * (不建议)也可以只用一个变量标记第一行第一列是否有0 8 | * @note 9 | */ 10 | #include "../header.hpp" 11 | 12 | class Solution 13 | { 14 | public: 15 | void setZeroes(vector> &matrix) 16 | { 17 | int m = matrix.size(), n = matrix[0].size(); 18 | bool row1_zero = false, 19 | col1_zero = false; // indicate whether first row and col has 0 20 | for (int i = 0; i < m; i++) 21 | { 22 | if (!matrix[i][0]) { col1_zero = true; } 23 | } 24 | for (int j = 0; j < n; j++) 25 | { 26 | if (!matrix[0][j]) { row1_zero = true; } 27 | } 28 | 29 | // set first row and col to 0 given matrix[i][j] 30 | for (int i = 1; i < m; i++) 31 | { 32 | for (int j = 1; j < n; j++) 33 | { 34 | if (!matrix[i][j]) { matrix[i][0] = matrix[0][j] = 0; } 35 | } 36 | } 37 | 38 | // set matrix[i][j] to 0 given the result of first row and col 39 | for (int i = 1; i < m; i++) 40 | { 41 | for (int j = 1; j < n; j++) 42 | { 43 | if (!matrix[i][0] || !matrix[0][j]) { matrix[i][j] = 0; } 44 | } 45 | } 46 | 47 | for (int i = 0; i < m; i++) 48 | { 49 | if (col1_zero) { matrix[i][0] = 0; } 50 | } 51 | for (int j = 0; j < n; j++) 52 | { 53 | if (row1_zero) { matrix[0][j] = 0; } 54 | } 55 | } 56 | }; 57 | 58 | // 只使用一个标记的版本 59 | class Solution2 60 | { 61 | public: 62 | void setZeroes(vector> &matrix) 63 | { 64 | int m = matrix.size(); 65 | int n = matrix[0].size(); 66 | int flag_col0 = false; 67 | for (int i = 0; i < m; i++) 68 | { 69 | if (!matrix[i][0]) { flag_col0 = true; } 70 | for (int j = 1; j < n; j++) 71 | { 72 | if (!matrix[i][j]) { matrix[i][0] = matrix[0][j] = 0; } 73 | } 74 | } 75 | for (int i = m - 1; i >= 0; i--) 76 | { 77 | for (int j = 1; j < n; j++) 78 | { 79 | if (!matrix[i][0] || !matrix[0][j]) { matrix[i][j] = 0; } 80 | } 81 | if (flag_col0) { matrix[i][0] = 0; } 82 | } 83 | } 84 | }; 85 | 86 | int main(int argc, char const *argv[]) 87 | { 88 | Solution s; 89 | return 0; 90 | } -------------------------------------------------------------------------------- /Array/77.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 77[M]. 组合 3 | * @details 4 | * @url https://leetcode.cn/problems/combinations 5 | * @idea 递归回溯 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | vector> combine(int n, int k) 14 | { 15 | vector> res; 16 | vector curr; 17 | backtrace(n, k, res, curr, 1); 18 | return res; 19 | } 20 | 21 | void backtrace(int n, int k, vector> &res, vector &curr, int start) 22 | { 23 | if (curr.size() == k) 24 | { 25 | res.push_back(curr); 26 | return; 27 | } 28 | 29 | // n - i + 1 >= k -curr.size是剪枝操作,当剩余的数组不足以完整枚举的时候就提前停止遍历 30 | for (int i = start; n - i + 1 >= k - curr.size(); i++) 31 | { 32 | curr.push_back(i); 33 | backtrace(n, k, res, curr, i + 1); 34 | curr.pop_back(); 35 | } 36 | } 37 | }; 38 | 39 | int main(int argc, char const *argv[]) 40 | { 41 | Solution s; 42 | return 0; 43 | } -------------------------------------------------------------------------------- /DP/1035.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 1035[M].不相交的线 3 | * @details 4 | * @url 5 | * @idea 和1143不相交的线本质是一样的,题解都一模一样 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int maxUncrossedLines(vector &nums1, vector &nums2) 14 | { 15 | int n1 = nums1.size(); 16 | int n2 = nums2.size(); 17 | 18 | vector> dp(n1 + 1, vector(n2 + 1, 0)); 19 | for (int i = 1; i <= n1; i++) 20 | { 21 | for (int j = 1; j <= n2; j++) 22 | { 23 | if (nums1[i - 1] == nums2[j - 1]) { dp[i][j] = dp[i - 1][j - 1] + 1; } 24 | else { dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); } 25 | } 26 | } 27 | return dp[n1][n2]; 28 | } 29 | }; 30 | 31 | int main(int argc, char const *argv[]) 32 | { 33 | Solution s; 34 | return 0; 35 | } -------------------------------------------------------------------------------- /DP/1143.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 1143.最长公共子序列 3 | * @details 4 | * @url https://leetcode.cn/problems/longest-common-subsequence/description/ 5 | * @idea 二维动态规划,dp[i][j] 表示 text 1[0:i] 和 text2[0:j] 的最长公共子序列的长度。 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int longestCommonSubsequence(string text1, string text2) 14 | { 15 | int n1 = text1.size(), n2 = text2.size(); 16 | vector> dp(n1 + 1, vector(n2 + 1, 0)); 17 | // NOTE: idx of string starts from 0 while idx of dp starts from 1 18 | for (int i = 1; i <= n1; i++) 19 | { 20 | for (int j = 1; j <= n2; j++) 21 | { 22 | if (text1[i - 1] == text2[j - 1]) { dp[i][j] = dp[i - 1][j - 1] + 1; } 23 | else { dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]); } 24 | } 25 | } 26 | return dp[n1][n2]; 27 | } 28 | }; 29 | 30 | int main(int argc, char const *argv[]) 31 | { 32 | Solution s; 33 | string s1 = "abcde", s2 = "ace"; 34 | int max_len = s.longestCommonSubsequence(s1, s2); 35 | cout << max_len; 36 | } -------------------------------------------------------------------------------- /DP/115.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 115[H].不同的子序列 3 | * @details 4 | * @url https://leetcode.cn/problems/distinct-subsequences/description/ 5 | * @idea dp[i][j] 表示在 s[i:] 的子序列中 t[j:] 出现的个数,倒序递推. s[i] == 6 | * t[j]时有两种选择,加上这两个字符构成匹配还是只考虑s[i+1]的匹配,两种选择相加 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | public: 14 | int numDistinct(string s, string t) 15 | { 16 | int s_size = s.size(); 17 | int t_size = t.size(); 18 | if (s_size < t_size) return 0; 19 | vector> dp(s_size + 1, 20 | vector(t_size + 1, 0)); 21 | // when len(t)=t_size, empty str must be sub-seq 22 | for (int i = 0; i <= s_size; i++) // NOTE: <= 23 | { 24 | dp[i][t_size] = 1; 25 | } 26 | 27 | for (int i = s_size - 1; i >= 0; i--) 28 | { 29 | for (int j = t_size - 1; j >= 0; j--) 30 | { 31 | if (s[i] == t[j]) { dp[i][j] = dp[i + 1][j + 1] + dp[i + 1][j]; } 32 | else { dp[i][j] = dp[i + 1][j]; } 33 | } 34 | } 35 | return dp[0][0]; 36 | } 37 | }; 38 | 39 | int main(int argc, char const *argv[]) 40 | { 41 | Solution s; 42 | return 0; 43 | } -------------------------------------------------------------------------------- /DP/120.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 120. 三角形最短路径和 3 | * @details 4 | * @url https://leetcode.cn/problems/triangle/description/ 5 | * @idea DP,注意斜边的初始化和状态转移规则 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int minimumTotal(vector> &triangle) 14 | { 15 | int m = triangle.size(); 16 | vector> dp; 17 | vector first_row; 18 | first_row.emplace_back(triangle[0][0]); 19 | dp.emplace_back(first_row); 20 | for (int i = 1; i < m; i++) 21 | { 22 | int n = triangle[i].size(); 23 | vector dp_row(n); 24 | dp_row[0] = dp[i - 1][0] + triangle[i][0]; 25 | dp_row[n - 1] = dp[i - 1][n - 2] + triangle[i][n - 1]; 26 | dp.emplace_back(dp_row); 27 | } 28 | 29 | for (int i = 2; i < m; i++) 30 | { 31 | for (int j = 1; j < dp[i].size() - 1; j++) 32 | { 33 | dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j]) + triangle[i][j]; 34 | } 35 | } 36 | PrintMatrix(dp); 37 | 38 | int min_cost = dp[m - 1][0]; 39 | for (int j = 1; j < triangle[m - 1].size(); j++) { min_cost = min(min_cost, dp[m - 1][j]); } 40 | 41 | return min_cost; 42 | } 43 | }; 44 | 45 | int main(int argc, char const *argv[]) 46 | { 47 | vector> tri = { 48 | {2}, 49 | {3, 4}, 50 | {6, 5, 7}, 51 | {4, 1, 8, 3}, 52 | }; 53 | Solution s; 54 | int min_cost = s.minimumTotal(tri); 55 | cout << min_cost << endl; 56 | } -------------------------------------------------------------------------------- /DP/122.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 122.买卖股票的最佳时机2 3 | * @details 4 | * @url https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/description/ 5 | * @idea n*2维的dp数组,dp[i]表示当天的最大利润,2维表示当天是否持有股票. 0表示没有股票,1表示有股票 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int maxProfit(vector &prices) 14 | { 15 | int n = prices.size(); 16 | vector> dp(n, vector(2, 0)); 17 | dp[0][1] = -prices[0]; 18 | for (int i = 1; i < n; i++) 19 | { 20 | dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i]); 21 | dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - prices[i]); 22 | } 23 | return dp[n - 1][0]; 24 | } 25 | }; 26 | 27 | int main(int argc, char const *argv[]) 28 | { 29 | Solution s; 30 | return 0; 31 | } -------------------------------------------------------------------------------- /DP/1277.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 1277. 统计全为 1 的正方形子矩阵 3 | * @details 4 | * @url https://leetcode.cn/problems/count-square-submatrices-with-all-ones/ 5 | * @idea 6 | * dp[i][j]表示坐标i,j处的最大正方形数量,状态转移考虑左上角3个格子的正方形数量,取min(由于木桶效应)。 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | public: 14 | int countSquares(vector> &matrix) 15 | { 16 | int m = matrix.size(); 17 | int n = matrix[0].size(); 18 | vector> dp(m, vector(n, 0)); 19 | dp[0][0] = matrix[0][0]; 20 | int max_num = 0; 21 | for (int i = 0; i < m; i++) 22 | { 23 | for (int j = 0; j < n; j++) 24 | { 25 | if (i == 0 || j == 0) { dp[i][j] = matrix[i][j]; } 26 | else if (matrix[i][j] == 0) { dp[i][j] = 0; } 27 | else { dp[i][j] = min(min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1; } 28 | max_num += dp[i][j]; 29 | } 30 | } 31 | return max_num; 32 | } 33 | }; 34 | 35 | int main(int argc, char const *argv[]) 36 | { 37 | Solution s; 38 | return 0; 39 | } -------------------------------------------------------------------------------- /DP/152.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 152.乘积最大子数组 3 | * @details 4 | * @url https://leetcode.cn/problems/maximum-product-subarray/description/ 5 | * @idea 6 | * 由于有复数存在,要维护两个dp,一个算最大值一个算最小值,因为负的越大,再乘一个负数就有可能更大 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | public: 14 | int maxProduct(vector &nums) 15 | { 16 | int n = nums.size(); 17 | vector dp_max(nums.begin(), nums.end()); 18 | vector dp_min(nums.begin(), nums.end()); 19 | long long max_num = nums[0]; 20 | for (int i = 1; i < n; i++) 21 | { 22 | // 由于用原数组进行了初始化,因此max和min谁在前谁在后无所谓 23 | dp_min[i] = min((long)nums[i], min(dp_max[i - 1] * nums[i], dp_min[i - 1] * nums[i])); 24 | dp_max[i] = max((long)nums[i], max(dp_max[i - 1] * nums[i], dp_min[i - 1] * nums[i])); 25 | 26 | // 单纯用来逃leetcode的不合理测试用例,无意义 27 | if (dp_min[i] < INT_MIN) { dp_min[i] = nums[i]; } 28 | 29 | max_num = max((long)max_num, max(dp_max[i], dp_min[i])); 30 | } 31 | return max_num; 32 | } 33 | }; 34 | 35 | int main(int argc, char const *argv[]) 36 | { 37 | Solution s; 38 | vector ar = {-1, -2, -9, -6}; 39 | int ans = s.maxProduct(ar); 40 | cout << ans << endl; 41 | } -------------------------------------------------------------------------------- /DP/198.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 198.打家劫舍 3 | * @details 4 | * @url https://leetcode.cn/problems/house-robber/description/ 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int rob(vector &nums) 14 | { 15 | int n = nums.size(); 16 | if (!n) 17 | return 0; 18 | else if (n == 1) 19 | return nums[0]; 20 | vector dp(n); 21 | dp[0] = nums[0]; 22 | dp[1] = max(nums[0], nums[1]); 23 | for (int i = 2; i < n; i++) 24 | { 25 | dp[i] = max(dp[i - 1], nums[i] + dp[i - 2]); 26 | } 27 | return dp[n - 1]; 28 | } 29 | }; 30 | 31 | int main(int argc, char const *argv[]) 32 | { 33 | Solution s; 34 | } -------------------------------------------------------------------------------- /DP/213.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 213[M].打家劫舍 II 3 | * @details 4 | * @url https://leetcode.cn/problems/house-robber-ii/ 5 | * @idea 思路沿用 6 | * 198,由于首尾相连,不能同时偷第一家和最后一家,因此对下标范围进行两种特殊讨论即可,然后取最大的。 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | public: 14 | int rob(vector &nums) 15 | { 16 | int n = nums.size(); 17 | if (!n) 18 | return 0; 19 | else if (n == 1) 20 | return nums[0]; 21 | else if (n == 2) 22 | return max(nums[0], nums[1]); 23 | 24 | int ans = max(get_max(nums, 0, n - 2), get_max(nums, 1, n - 1)); 25 | return ans; 26 | } 27 | 28 | int get_max(vector &nums, int st, int ed) 29 | { 30 | int n = nums.size(); 31 | vector dp(n, 0); 32 | dp[st] = nums[st]; 33 | dp[st + 1] = max(nums[st], nums[st + 1]); 34 | 35 | for (int i = st + 2; i <= ed; i++) 36 | { 37 | dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]); 38 | } 39 | 40 | return dp[ed]; 41 | } 42 | }; 43 | 44 | int main(int argc, char const *argv[]) 45 | { 46 | Solution s; 47 | return 0; 48 | } -------------------------------------------------------------------------------- /DP/221.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 221.最大正方形 3 | * @details 4 | * @url https://leetcode.cn/problems/maximal-square/ 5 | * @idea 跟1277一样,状态转移方程完全一致,改一下统计方式,注意输入的是char不是int 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int maximalSquare(vector> &matrix) 14 | { 15 | int m = matrix.size(); 16 | int n = matrix[0].size(); 17 | vector> dp(m, vector(n, 0)); 18 | int max_size = 0; 19 | for (int i = 0; i < m; i++) 20 | { 21 | for (int j = 0; j < n; j++) 22 | { 23 | if (i == 0 || j == 0) { dp[i][j] = matrix[i][j] - '0'; } 24 | else if (matrix[i][j] == '0') { dp[i][j] == 0; } 25 | else { dp[i][j] = min(min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1; } 26 | max_size = max(max_size, dp[i][j]); 27 | } 28 | } 29 | return max_size * max_size; 30 | } 31 | }; 32 | 33 | int main(int argc, char const *argv[]) 34 | { 35 | Solution s; 36 | return 0; 37 | } -------------------------------------------------------------------------------- /DP/300.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 300. 最长递增子序列 3 | * @details 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 4 | * @url https://leetcode.cn/problems/longest-increasing-subsequence/ 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int lengthOfLIS(vector &nums) 14 | { 15 | int n = nums.size(); 16 | vector dp(n, 1); // dp[i] means longest sequence at idx i 17 | int max_len = 1; 18 | for (int i = 1; i < n; i++) 19 | { 20 | for (int j = 0; j < i; j++) 21 | { 22 | if (nums[j] < nums[i]) { dp[i] = max(dp[i], dp[j] + 1); } 23 | } 24 | max_len = max(max_len, dp[i]); 25 | } 26 | return max_len; 27 | } 28 | }; 29 | 30 | int main(int argc, char const *argv[]) 31 | { 32 | Solution s; 33 | vector seqs = {10, 9, 2, 5, 3, 7, 101, 18}; 34 | int max_len = s.lengthOfLIS(seqs); 35 | cout << max_len << endl; 36 | } -------------------------------------------------------------------------------- /DP/32.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 32. 最长有效括号 3 | * @details 4 | * @url https://leetcode.cn/problems/longest-valid-parentheses/description/ 5 | * @idea 动态规划,dp[i] 表示以下标 i 字符结尾的最长有效括号的长度; 6 | * 或者用栈其实最简单,每次匹配到括号后算一次长度即可 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | public: 14 | int longestValidParentheses(string s) 15 | { 16 | vector dp(s.size(), 0); // stores the max parenthes length at [i] 17 | 18 | int max_len = 0; 19 | for (int i = 1; i < s.size(); i++) 20 | { 21 | // case 1: () 22 | if (s[i] == ')' && s[i - 1] == '(') 23 | { 24 | dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2; 25 | } // NOTE: index is i-2 26 | 27 | // case 2: ((...)) 28 | if (s[i] == ')' && s[i - 1] == ')') 29 | { 30 | if (i > dp[i - 1] && s[i - 1 - dp[i - 1]] == '(') 31 | { 32 | dp[i] = dp[i - 1] + 2 + (i >= 2 + dp[i - 1] ? dp[i - 1 - dp[i - 1] - 1] : 0); 33 | } 34 | } 35 | max_len = max(max_len, dp[i]); 36 | } 37 | 38 | return max_len; 39 | } 40 | 41 | /** 42 | * @brief use stack 43 | * 44 | * @param s 45 | * @return int 46 | */ 47 | int longestValidParentheses2(string s) 48 | { 49 | stack st; // store index of ( 50 | st.push(-1); // NOTE: important to preserve feasibility 51 | int size = s.size(); 52 | if (size == 0) return 0; 53 | int max_len = 0; 54 | for (int i = 0; i < size; i++) 55 | { 56 | if (s[i] == '(') { st.push(i); } 57 | else 58 | { 59 | st.pop(); // pop here since we want to know the index of last paired parenthes 60 | if (st.empty()) 61 | st.push(i); 62 | else { max_len = max(max_len, i - st.top()); } 63 | } 64 | } 65 | return max_len; 66 | } 67 | }; 68 | 69 | int main(int argc, char const *argv[]) { Solution s; } -------------------------------------------------------------------------------- /DP/322.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 322.零钱兑换 3 | * @details 4 | * @url 5 | * https://leetcode.cn/problems/coin-change/solutions/132979/322-ling-qian-dui-huan-by-leetcode-solution/ 6 | * @idea 动态规划,从0开始攒总金额,每一步能凑的钱都基于上一步,看这次用什么面值的硬币 7 | * 舍硬币面值为c_j,F(i)为凑成面值i所需的最小硬币数,则状态转移方程为 8 | * F(i) = min(F(i-c_j))+1, for all c_j in C^R 9 | * @note 10 | */ 11 | #include "../header.hpp" 12 | 13 | class Solution 14 | { 15 | public: 16 | int coinChange(vector &coins, int amount) 17 | { 18 | int max_coin_num = amount + 1; 19 | vector F(amount + 1, max_coin_num); // 多了一个0,因此要+1 20 | F[0] = 0; 21 | for (int i = 1; i <= amount; i++) 22 | { 23 | for (int j = 0; j < coins.size(); j++) // traverse coin combination 24 | { 25 | if (coins[j] <= i) // NOTE: don't forget this step! used to judge wether the current 26 | // coin's value can constitute the final amount 27 | { 28 | F[i] = min(F[i], F[i - coins[j]] + 1); // choose use which value of coin to use 29 | } 30 | } 31 | return F[amount] > amount ? -1 : F[amount]; 32 | } 33 | } 34 | }; 35 | int main(int argc, char const *argv[]) 36 | { 37 | Solution s; 38 | vector coins{1, 2, 5}; 39 | int min_num = s.coinChange(coins, 11); 40 | printf("min num is:%d\r\n", min_num); 41 | return 0; 42 | } -------------------------------------------------------------------------------- /DP/343.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 343.整数拆分 3 | * @details 4 | * @url https://leetcode.cn/problems/integer-break/ 5 | * @idea DP,dp[i]表示把数字i拆解后的最大成乘积,状态转移在不拆、只拆一次和递归拆分中最大的 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int integerBreak(int n) 14 | { 15 | vector dp(n + 1); 16 | dp[0] = 0, dp[1] = 1; 17 | for (int i = 2; i <= n; i++) 18 | { 19 | // 拆分成j和i-j, 看j是否继续拆分 20 | for (int j = 1; j < i; j++) { dp[i] = max(dp[i], max(j * (i - j), (i - j) * dp[j])); } 21 | } 22 | return dp[n]; 23 | } 24 | }; 25 | 26 | int main(int argc, char const *argv[]) 27 | { 28 | Solution s; 29 | cout << s.integerBreak(10); 30 | return 0; 31 | } -------------------------------------------------------------------------------- /DP/343.py: -------------------------------------------------------------------------------- 1 | """ 2 | 343. 整数拆分 3 | https://leetcode.cn/problems/integer-break/description/ 4 | """ 5 | class Solution: 6 | def integerBreak(self, n: int) -> int: 7 | dp = [0] * (n+1) 8 | # dp[1] = 0 -> 0*1=0 9 | for i in range(2,n+1): 10 | for j in range(i): 11 | dp[i] = max(dp[i],j*(i-j),j*dp[i-j]) 12 | return dp[n] -------------------------------------------------------------------------------- /DP/392.cc: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public: 3 | bool isSubsequence(string s, string t) { 4 | int n = s.length(), m = t.length(); 5 | int i = 0, j = 0; 6 | while (i < n && j < m) { 7 | if (s[i] == t[j]) { 8 | i++; 9 | } 10 | j++; 11 | } 12 | return i == n; 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /DP/42.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 42[H].接雨水 3 | * @details 4 | * @url https://leetcode.cn/problems/trapping-rain-water/description/ 5 | * @idea 维护两个一维dp,分别表示左边最高柱子和右边最高柱子,最后取min算差值 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int trap(vector &height) 14 | { 15 | int n = height.size(); 16 | vector left(n); 17 | vector right(n); 18 | 19 | left[0] = height[0]; 20 | right[n - 1] = height[n - 1]; 21 | 22 | for (int i = 1; i < n; i++) 23 | { 24 | left[i] = max(height[i], left[i - 1]); 25 | } 26 | for (int i = n - 2; i >= 0; i--) 27 | { 28 | right[i] = max(height[i], right[i + 1]); 29 | } 30 | // PrintVector(left); 31 | // PrintVector(right); 32 | 33 | int sum = 0; 34 | for (int i = 1; i < n; i++) 35 | { 36 | int diff_h = min(left[i], right[i]) - height[i]; 37 | if (diff_h > 0) sum += diff_h; 38 | } 39 | return sum; 40 | } 41 | }; 42 | 43 | int main(int argc, char const *argv[]) 44 | { 45 | Solution s; 46 | vector height = {0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1}; 47 | cout << s.trap(height); 48 | return 0; 49 | } -------------------------------------------------------------------------------- /DP/516.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 516.最长回文子串 3 | * @details 4 | * @url https://leetcode.cn/problems/longest-palindromic-subsequence/description/ 5 | * @idea dp(i,j) 表示字符串 s 的第 i 到 j 个字母组成的串是否为回文串, 6 | * 初始化单个字符是回文,枚举字符串长度,判断 i...j 之间是否是回文。如果 i,j 7 | * 的字符相同就给子串的dp+2,否则通过内截的子串是否是回文来判断 8 | * @note 9 | */ 10 | #include "../header.hpp" 11 | 12 | class Solution 13 | { 14 | public: 15 | int longestPalindromeSubseq(string s) 16 | { 17 | int n = s.size(); 18 | vector> dp(n, vector(n)); 19 | 20 | for (int i = 0; i < n; i++) { dp[i][i] = 1; } 21 | 22 | for (int i = n - 1; i >= 0; i--) // NOTE:外层循环要从右边开始 23 | { 24 | for (int j = i + 1; j < n; j++) 25 | { 26 | if (s[i] == s[j]) { dp[i][j] = dp[i + 1][j - 1] + 2; } 27 | else { dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]); } 28 | } 29 | } 30 | 31 | return dp[0][n - 1]; 32 | } 33 | }; 34 | 35 | int main(int argc, char const *argv[]) 36 | { 37 | Solution s; 38 | return 0; 39 | } -------------------------------------------------------------------------------- /DP/518.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 3 | * @details 4 | * @url 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int functionName() 14 | { 15 | return 0; 16 | } 17 | }; 18 | 19 | int main(int argc, char const *argv[]) 20 | { 21 | Solution s; 22 | return 0; 23 | } -------------------------------------------------------------------------------- /DP/53.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 53.最大子数组和 3 | * @details 4 | * @url https://leetcode.cn/problems/maximum-subarray/description/ 5 | * @idea dp[i]顺着叠加就行 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int maxSubArray(vector &nums) 14 | { 15 | int n = nums.size(); 16 | vector dp(n, 0); 17 | dp[0] = nums[0]; 18 | int max_sum = dp[0]; 19 | for (int i = 1; i < n; i++) 20 | { 21 | dp[i] = max(nums[i], 22 | dp[i - 1] + nums[i]); // NOTE: since we demand the sequence be consecutive, 23 | // the new sub-sequence may start from new nums[i] 24 | max_sum = max(max_sum, 25 | dp[i]); // again, the Continuity results in max value may exist in mid pos 26 | } 27 | return max_sum; 28 | } 29 | }; 30 | 31 | int main(int argc, char const *argv[]) 32 | { 33 | Solution s; 34 | vector ar = {-2, 1, -3, 4, -1, 2, 1, -5, 4}; 35 | int ans = s.maxSubArray(ar); 36 | cout << ans << endl; 37 | } -------------------------------------------------------------------------------- /DP/583.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 583.两个字符串的删除操作 3 | * @details 4 | * @url https://leetcode.cn/problems/delete-operation-for-two-strings/description/ 5 | * @idea 1143的变种。可以先找最长公共子序列,然后比较两个串的删除次数谁更少。 6 | * 或者可以直接dp,dp[i][j]表示到串1的i和串2的j为止,删除所需的最小次数,递推时判断字符是否相等,如果相等直接递归到子串; 7 | * 否则看删除哪一个串的字符,然后从中找次数最少的 8 | * @note 9 | */ 10 | #include "../header.hpp" 11 | 12 | class Solution 13 | { 14 | public: 15 | int minDistance(string word1, string word2) 16 | { 17 | int n1 = word1.size(), n2 = word2.size(); 18 | vector> dp(n1 + 1, vector(n2 + 1, 0)); // NOTE: 注意初始化的大小 19 | 20 | // 要让空串和非空串相等,只能完全删除另一个 21 | for (int j = 1; j <= n2; j++) { dp[0][j] = j; } 22 | for (int i = 1; i <= n1; i++) { dp[i][0] = i; } 23 | 24 | for (int i = 1; i <= n1; i++) 25 | { 26 | for (int j = 1; j <= n2; j++) 27 | { 28 | if (word1[i - 1] == word2[j - 1]) // 字符串需要从0开始遍历 29 | { 30 | dp[i][j] = dp[i - 1][j - 1]; 31 | } 32 | else { dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + 1; } 33 | } 34 | } 35 | return dp[n1][n2]; 36 | } 37 | }; 38 | 39 | int main(int argc, char const *argv[]) 40 | { 41 | Solution s; 42 | return 0; 43 | } -------------------------------------------------------------------------------- /DP/62.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 62.不同路径 3 | * @details 4 | * @url https://leetcode.cn/problems/unique-paths/description/?envType=study-plan-v2&envId=dynamic-programming 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int uniquePaths(int m, int n) 14 | { 15 | // dp[i][j] = dp[i-1][j] + dp[i][j-1] 16 | vector> dp(m, vector(n)); 17 | for (int i = 0; i < m; i++) 18 | dp[i][0] = 1; 19 | for (int j = 0; j < n; j++) 20 | dp[0][j] = 1; 21 | 22 | for (int i = 1; i < m; i++) 23 | { 24 | for (int j = 1; j < n; j++) 25 | { 26 | dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; 27 | } 28 | } 29 | return dp[m - 1][n - 1]; 30 | } 31 | }; 32 | 33 | int main(int argc, char const *argv[]) 34 | { 35 | Solution s; 36 | } -------------------------------------------------------------------------------- /DP/62.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://leetcode.cn/problems/unique-paths/description/?envType=study-plan-v2&envId=dynamic-programming 3 | """ 4 | 5 | import numpy as np 6 | class Solution: 7 | def uniquePaths(self, m: int, n: int) -> int: 8 | dp = np.zeros((m, n)) 9 | dp[0, :] = 1 10 | dp[:, 0] = 1 11 | for i in range(1,m): 12 | for j in range(1,n): 13 | dp[i,j] = dp[i-1][j] + dp[i][j-1] 14 | 15 | return int(dp[m-1,n-1]) 16 | -------------------------------------------------------------------------------- /DP/63.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 63.不同路径2。考虑障碍物的存在 3 | * @details 4 | * @url 5 | * https://leetcode.cn/problems/unique-paths-ii/description/?envType=study-plan-v2&envId=dynamic-programming 6 | * @idea 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | public: 14 | int uniquePathsWithObstacles(vector> &obstacleGrid) 15 | { 16 | int m = obstacleGrid.size(), n = obstacleGrid[0].size(); 17 | vector> dp(m, vector(n)); 18 | if (n == 0) return 0; 19 | if (obstacleGrid[0][0] == 1) 20 | return 0; 21 | else 22 | dp[0][0] = 1; 23 | 24 | for (int i = 1; i < m; i++) 25 | { 26 | if (obstacleGrid[i][0] == 0 && dp[i - 1][0] != 0) 27 | dp[i][0] = 1; 28 | else 29 | dp[i][0] = 0; 30 | } 31 | for (int j = 1; j < n; j++) 32 | { 33 | if (obstacleGrid[0][j] == 0 && dp[0][j - 1] != 0) 34 | dp[0][j] = 1; 35 | else 36 | dp[0][j] = 0; 37 | } 38 | 39 | for (int i = 1; i < m; i++) 40 | { 41 | for (int j = 1; j < n; j++) 42 | { 43 | if (obstacleGrid[i][j] == 1) { continue; } 44 | else { dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; } 45 | } 46 | } 47 | return dp[m - 1][n - 1]; 48 | } 49 | }; 50 | 51 | class Solution2 52 | { 53 | public: 54 | int uniquePathsWithObstacles(vector> &obstacleGrid) 55 | { 56 | int n = obstacleGrid.size(), m = obstacleGrid.at(0).size(); 57 | vector f(m); 58 | 59 | f[0] = (obstacleGrid[0][0] == 0); 60 | for (int i = 0; i < n; ++i) 61 | { 62 | for (int j = 0; j < m; ++j) 63 | { 64 | if (obstacleGrid[i][j] == 1) 65 | { 66 | f[j] = 0; 67 | continue; 68 | } 69 | if (j - 1 >= 0 && obstacleGrid[i][j - 1] == 0) // NOTE: start idx 70 | { 71 | f[j] += f[j - 1]; // NOTE:!! 72 | } 73 | } 74 | } 75 | 76 | return f.back(); 77 | } 78 | }; 79 | 80 | int main(int argc, char const *argv[]) { Solution s; } -------------------------------------------------------------------------------- /DP/64.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 64.最小路径和 3 | * @details 4 | * @url https://leetcode.cn/problems/minimum-path-sum/description/?envType=study-plan-v2&envId=dynamic-programming 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int minPathSum(vector> &grid) 14 | { 15 | int m = grid.size(), n = grid[0].size(); 16 | if (m == 0 || n == 0) 17 | { 18 | return 0; 19 | } 20 | vector> dp(m, vector(n)); 21 | dp[0][0] = grid[0][0]; 22 | for (int i = 1; i < m; i++) 23 | dp[i][0] = dp[i - 1][0] + grid[i][0]; 24 | for (int j = 1; j < n; j++) 25 | dp[0][j] = dp[0][j - 1] + grid[0][j]; 26 | 27 | for (int i = 1; i < m; i++) 28 | { 29 | for (int j = 1; j < n; j++) 30 | { 31 | dp[i][j] = min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j]; 32 | } 33 | } 34 | return dp[m - 1][n - 1]; 35 | } 36 | }; 37 | 38 | int main(int argc, char const *argv[]) 39 | { 40 | Solution s; 41 | } -------------------------------------------------------------------------------- /DP/64.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | import numpy as np 3 | 4 | class Solution: 5 | def minPathSum(self, grid: List[List[int]]) -> int: 6 | # dp = [[0] * len(grid) for _ in len(grid[0])] 7 | row = len(grid) 8 | col = len(grid[0]) 9 | dp = np.zeros((row,col)) 10 | dp[0][0] = grid[0][0] 11 | for i in range (1,row): 12 | dp[i][0] = dp[i-1][0] + grid[i][0] 13 | for j in range (1,col): 14 | dp[0][j] = dp[0][j-1] + grid[0][j] 15 | for i in range(1,row): 16 | for j in range(1,col): 17 | dp[i][j] = min(dp[i-1,j],dp[i,j-1]) + grid[i][j] 18 | 19 | return int(dp[row-1][col-1]) 20 | 21 | -------------------------------------------------------------------------------- /DP/647.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 647.回文子串 3 | * @details 输出字符串中所有的回文串 4 | * @url https://leetcode.cn/problems/palindromic-substrings/description/ 5 | * @idea dp[i][j]递推i到j之间的回文串 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int countSubstrings(string s) 14 | { 15 | int n = s.size(); 16 | vector> dp(n, vector(n, false)); 17 | 18 | int num = 0; 19 | for (int i = n - 1; i >= 0; i--) // 注意遍历顺序 20 | { 21 | for (int j = i; j < n; j++) // 注意起点 22 | { 23 | if (s[i] == s[j]) // 注意分情况判断 24 | { 25 | if (j - i <= 1) 26 | { 27 | dp[i][j] = true; 28 | num++; 29 | } 30 | else if (dp[i + 1][j - 1]) 31 | { 32 | dp[i][j] = true; 33 | num++; 34 | } 35 | } 36 | } 37 | } 38 | return num; 39 | } 40 | }; 41 | 42 | int main(int argc, char const *argv[]) 43 | { 44 | Solution s; 45 | return 0; 46 | } -------------------------------------------------------------------------------- /DP/70.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 70.爬楼梯 3 | * @details 4 | * @url 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int climbStairs(int n) 14 | { 15 | int llast = 1; 16 | int last = 1; 17 | int curr; 18 | for (int i = 1; i <= n - 1; i++) // n-1 because the first two numbers are initialized 19 | { 20 | curr = last + llast; 21 | llast = last; 22 | last = curr; 23 | } 24 | return curr; 25 | } 26 | int climbStairsAr(int n) 27 | { 28 | vector dp(n + 1); 29 | dp[0] = 1; 30 | dp[1] = 1; 31 | for (int i = 2; i <= n; i++) { dp[i] = dp[i - 1] + dp[i - 2]; } 32 | return dp[n]; 33 | } 34 | }; 35 | 36 | int main(int argc, char const *argv[]) 37 | { 38 | Solution s; 39 | int rst = s.climbStairs(3); 40 | printf("%d", rst); 41 | } -------------------------------------------------------------------------------- /DP/718.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 718. 最长重复子数组 3 | * @details 4 | * @url https://leetcode.cn/problems/maximum-length-of-repeated-subarray/description/ 5 | * @idea 二维动态规划.dp[i][j] 表示 A[i:] 和 B[j:] 的最长公共前缀,答案为所有 dp[i][j] 6 | * 中的最大值. 如果 A[i] == B[j], dp[i][j] = dp[i -1][j - 1] + 1,否则为 0. i/j为0时单独处理 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | public: 14 | int findLength(vector &nums1, vector &nums2) 15 | { 16 | int n1 = nums1.size(), n2 = nums2.size(); 17 | vector> dp(n1, vector(n2, 0)); 18 | int max_len = 0; 19 | for (int i = 0; i < n1; i++) 20 | { 21 | for (int j = 0; j < n2; j++) 22 | { 23 | if (nums1[i] == nums2[j]) 24 | { 25 | if (i == 0 || j == 0) { dp[i][j] = 1; } 26 | else { dp[i][j] = dp[i - 1][j - 1] + 1; } 27 | } 28 | else { dp[i][j] = 0; } 29 | max_len = max(max_len, dp[i][j]); 30 | } 31 | } 32 | return max_len; 33 | } 34 | }; 35 | 36 | int main(int argc, char const *argv[]) 37 | { 38 | Solution s; 39 | return 0; 40 | } -------------------------------------------------------------------------------- /DP/746.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 746. 最小话费爬楼梯 3 | * @details 4 | * @url https://leetcode.cn/problems/min-cost-climbing-stairs/description/?envType=study-plan-v2&envId=dynamic-programming 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int minCostClimbingStairs(vector &cost) 14 | { 15 | int n = cost.size(); 16 | vector dp(n + 1); 17 | dp[0] = 0; 18 | dp[1] = 0; 19 | for (int i = 2; i <= n; i++) 20 | { 21 | dp[i] = min(cost[i - 1] + dp[i - 1], cost[i - 2] + dp[i - 2]); 22 | } 23 | return dp[n]; 24 | } 25 | }; 26 | 27 | int main(int argc, char const *argv[]) 28 | { 29 | Solution s; 30 | } -------------------------------------------------------------------------------- /DP/790.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 790.多米诺平铺和拖米诺平铺 3 | * @details 4 | * @url https://leetcode.cn/problems/domino-and-tromino-tiling/description/ 5 | * @idea 6 | * 二维动态规划,dp[i][s]表示铺到第i列的时候状态s的铺法数量,要根据s=0123四种情况分类讨论状态转移 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | public: 14 | int numTilings(int n) 15 | { 16 | const long long mod = 1e9 + 7; 17 | vector> dp(n + 1, vector(4, 0)); 18 | dp[0][3] = 1; // 通过这种初始化可以强迫迭代第一列的时候只铺竖着的2格或者不铺 19 | 20 | for (int i = 1; i <= n; i++) // NOTE: must start from 1, end in n 21 | { 22 | dp[i][0] = (dp[i - 1][3]) % mod; 23 | dp[i][1] = (dp[i - 1][0] + dp[i - 1][2]) % mod; 24 | dp[i][2] = (dp[i - 1][0] + dp[i - 1][1]) % mod; 25 | dp[i][3] = (dp[i - 1][3] + dp[i - 1][2] + dp[i - 1][1] + dp[i - 1][0]) % mod; 26 | } 27 | return dp[n][3]; 28 | } 29 | }; 30 | 31 | int main(int argc, char const *argv[]) 32 | { 33 | Solution s; 34 | int num = s.numTilings(3); 35 | cout << num; 36 | return 0; 37 | } -------------------------------------------------------------------------------- /DP/931.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 931[M]. 下降路径最小和 3 | * @details 4 | * @url 5 | * https://leetcode.cn/problems/minimum-falling-path-sum/description/?envType=study-plan-v2&envId=dynamic-programming 6 | * @idea 注意第一行的初始化以及递推过程中列标的范围 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | public: 14 | int minFallingPathSum(vector> &matrix) 15 | { 16 | int m = matrix.size(), n = matrix[0].size(); 17 | vector> dp(m, vector(n, 0)); 18 | for (int j = 0; j < n; j++) 19 | { 20 | dp[0][j] = matrix[0][j]; 21 | } 22 | for (int i = 1; i < m; i++) 23 | { 24 | for (int j = 0; j < n; j++) 25 | { 26 | int tmp = dp[i - 1][j]; 27 | if (j > 0) { tmp = min(dp[i - 1][j - 1], tmp); } 28 | if (j < n - 1) { tmp = min(dp[i - 1][j + 1], tmp); } 29 | dp[i][j] = tmp + matrix[i][j]; 30 | } 31 | } 32 | int ans = INT_MAX; 33 | for (int j = 0; j < n; j++) 34 | { 35 | ans = min(ans, dp[m - 1][j]); 36 | } 37 | return ans; 38 | } 39 | }; 40 | 41 | int main(int argc, char const *argv[]) 42 | { 43 | Solution s; 44 | return 0; 45 | } -------------------------------------------------------------------------------- /DP/97.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 97[M].交错字符串 3 | * @details 4 | * @url https://leetcode.cn/problems/interleaving-string/description/ 5 | * @idea dp[i][j]表示 s1 的前 i 个和 s2 的前 j 个能否凑成 s3 的 i+j 个。dp 向后递推,考虑 s1 的前 i-1 6 | * 和 s2 的前 j 能否凑成 s3 的 i-1+j,注意要加字符的相等判断;s2 同理。 注意初始化方式 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | public: 14 | bool isInterleave(string s1, string s2, string s3) 15 | { 16 | int n1 = s1.size(), n2 = s2.size(), n3 = s3.size(); 17 | if (n1 + n2 != n3) return false; 18 | vector> dp(n1 + 1, vector(n2 + 1, false)); 19 | dp[0][0] = true; 20 | 21 | for (int i = 1; i <= n1; i++) 22 | { 23 | dp[i][0] = dp[i - 1][0] && s1[i - 1] == s3[i - 1]; 24 | } 25 | for (int j = 1; j <= n2; j++) 26 | { 27 | dp[0][j] = dp[0][j - 1] && s2[j - 1] == s3[j - 1]; 28 | } 29 | 30 | for (int i = 1; i <= n1; i++) 31 | { 32 | for (int j = 1; j <= n2; j++) 33 | { 34 | 35 | dp[i][j] = (dp[i - 1][j] && s1[i - 1] == s3[i - 1 + j]) || 36 | (dp[i][j - 1] && s2[j - 1] == s3[i + j - 1]); 37 | } 38 | } 39 | return dp[n1][n2]; 40 | } 41 | } 42 | 43 | ; 44 | 45 | int main(int argc, char const *argv[]) 46 | { 47 | Solution s; 48 | return 0; 49 | } -------------------------------------------------------------------------------- /DP/980.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brian00715/PnC-Interview-Coding/af5170352673544e84492f908664d79f0aed5b25/DP/980.cc -------------------------------------------------------------------------------- /DP/kama46.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 46.携带研究材料 3 | * @details 小明是一位科学家,他需要参加一场重要的国际科学大会,以展示自己的最新研究成果。 4 | * 他需要带一些研究材料,但是他的行李箱空间有限。这些研究材料包括实验设备、文献资料和实验样本等等, 5 | * 它们各自占据不同的空间,并且具有不同的价值。 6 | 小明的行李空间为 7 | N,问小明应该如何抉择,才能携带最大价值的研究材料,每种研究材料只能选择一次,并且只有选与不选两种选择,不能进行切割。 8 | * @url https://kamacoder.com/problempage.php?pid=1046 9 | * @idea 10 | * @note 11 | */ 12 | 13 | #include "../header.hpp" 14 | #include 15 | #include 16 | using namespace std; 17 | 18 | int main() 19 | { 20 | int cap, obj_num; 21 | vector space; 22 | vector value; 23 | cin >> obj_num; 24 | cin >> cap; 25 | for (int i = 0; i < obj_num; i++) 26 | { 27 | int tmp; 28 | cin >> tmp; 29 | space.push_back(tmp); 30 | } 31 | for (int i = 0; i < obj_num; i++) 32 | { 33 | int tmp; 34 | cin >> tmp; 35 | value.push_back(tmp); 36 | } 37 | // PrintVector(space); 38 | // PrintVector(value); 39 | 40 | vector> dp(obj_num, vector(cap + 1, 0)); 41 | 42 | for (int j = space[0]; j <= cap; j++) 43 | { 44 | dp[0][j] = value[0]; 45 | } 46 | 47 | for (int i = 1; i < obj_num; i++) 48 | { 49 | for (int j = 0; j <= cap; j++) 50 | { 51 | if (j < space[i]) { dp[i][j] = dp[i - 1][j]; } // 装不下当前物体,直接继承 52 | else { dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - space[i]] + value[i]); } 53 | } 54 | } 55 | cout << dp[obj_num - 1][cap]; 56 | } -------------------------------------------------------------------------------- /DataStructure/graph.cc: -------------------------------------------------------------------------------- 1 | #include "../header.hpp" 2 | class Graph 3 | { 4 | public: 5 | Graph(int size) : size(size) 6 | { 7 | adj = new int *[size]; 8 | for (int i = 0; i < size; i++) 9 | { 10 | adj[i] = new int[size]; 11 | for (int j = 0; j < size; j++) 12 | { 13 | adj[i][j] = 0; 14 | } 15 | } 16 | } 17 | void addEdge(int u, int v, float w) 18 | { 19 | adj[u][v] = w; 20 | } 21 | 22 | /** 23 | * @brief traverse from start to end. only output traverse path, not the path from start to end 24 | * 25 | */ 26 | void bfs(int start, int end) 27 | { 28 | bool *visited = new bool[size]; 29 | for (int i = 0; i < size; i++) 30 | { 31 | visited[i] = false; 32 | } 33 | 34 | std::queue q; 35 | q.push(start); 36 | visited[start] = true; 37 | 38 | cout << "BFS result: "; 39 | while (!q.empty()) 40 | { 41 | int u = q.front(); 42 | q.pop(); 43 | cout << u + 1 << " "; 44 | if (u == end) 45 | { 46 | std::cout << "Found" << std::endl; 47 | break; 48 | } 49 | // traverse all the adjacent nodes 50 | for (int i = 0; i < size; i++) 51 | { 52 | if (adj[u][i] != 0 && !visited[i]) 53 | { 54 | visited[i] = true; 55 | q.push(i); 56 | } 57 | } 58 | } 59 | cout << endl; 60 | } 61 | 62 | void dfs(int start, int end) 63 | { 64 | vector visited(size, false); 65 | 66 | std::stack s; 67 | s.push(start); 68 | visited[start] = true; 69 | cout << "DFS result: "; 70 | while (!s.empty()) 71 | { 72 | int u = s.top(); 73 | s.pop(); 74 | cout << u + 1 << " "; 75 | if (u == end) 76 | { 77 | std::cout << "Found" << std::endl; 78 | break; 79 | } 80 | // traverse all the adjacent nodes 81 | for (int i = 0; i < size; i++) 82 | { 83 | if (adj[u][i] != 0 && !visited[i]) 84 | { 85 | visited[i] = true; 86 | s.push(i); 87 | } 88 | } 89 | } 90 | cout << endl; 91 | } 92 | 93 | void printAdj() 94 | { 95 | for (int i = 0; i < size; i++) 96 | { 97 | std::cout << i << ": "; 98 | for (int j = 0; j < size; j++) 99 | { 100 | std::cout << adj[i][j] << " "; 101 | } 102 | std::cout << std::endl; 103 | } 104 | } 105 | 106 | float calcu_sum_weights(std::vector path) 107 | { 108 | float sum = 0; 109 | for (int i = 0; i < path.size() - 1; i++) 110 | { 111 | sum += adj[path[i]][path[i + 1]]; 112 | } 113 | return sum; 114 | } 115 | 116 | private: 117 | int **adj; 118 | int size; 119 | }; 120 | 121 | int main(int argc, char const *argv[]) 122 | { 123 | vector> input = { 124 | {1, 2, 3}, 125 | {1, 3, 2}, 126 | {1, 4, 1}, 127 | {2, 5, 2}, 128 | {3, 6, 1}, 129 | {4, 6, 4}, 130 | {4, 5, 3}, 131 | {6, 5, 3}}; 132 | int start = 1, end = 5; 133 | Graph g(input.size()); 134 | // build graph 135 | for (int i = 0; i < input.size(); i++) 136 | { 137 | g.addEdge(input[i][0] - 1, input[i][1] - 1, input[i][2]); 138 | } 139 | g.printAdj(); 140 | g.bfs(start - 1, end - 1); 141 | g.dfs(start - 1, end - 1); 142 | 143 | return 0; 144 | } 145 | -------------------------------------------------------------------------------- /DataStructure/link_list.cc: -------------------------------------------------------------------------------- 1 | #include "../header.hpp" 2 | 3 | class LinkList 4 | { 5 | private: 6 | struct Node 7 | { 8 | int data; 9 | Node *next; 10 | Node(int data) : data(data), next(nullptr) {} 11 | }; 12 | Node *head; 13 | 14 | public: 15 | LinkList() 16 | { 17 | head = nullptr; 18 | } 19 | 20 | void append(int data) 21 | { 22 | Node *newNode = new Node(data); 23 | if (head == nullptr) 24 | { 25 | head = newNode; 26 | return; 27 | } 28 | Node *p = head; 29 | // find the last node 30 | while (p->next != nullptr) 31 | { 32 | p = p->next; 33 | } 34 | p->next = newNode; 35 | } 36 | 37 | bool insert_after(int target_data, int new_data) 38 | { 39 | Node *newNode = new Node(new_data); 40 | if (head == nullptr) 41 | { 42 | head = newNode; 43 | return true; 44 | } 45 | Node *p = head; 46 | while (p != nullptr) 47 | { 48 | if (p->data == target_data) 49 | { 50 | newNode->next = p->next; 51 | p->next = newNode; 52 | return true; 53 | } 54 | p = p->next; 55 | } 56 | return false; 57 | } 58 | 59 | bool insert_before(int target_data, int new_data) 60 | { 61 | Node *newNode = new Node(new_data); 62 | if (head == nullptr) 63 | { 64 | head = newNode; 65 | return true; 66 | } 67 | Node *p = head; 68 | while (p->next != nullptr) 69 | { 70 | if (p->next->data == target_data) 71 | { 72 | newNode->next = p->next; 73 | p->next = newNode; 74 | return true; 75 | } 76 | p = p->next; 77 | } 78 | return false; 79 | } 80 | 81 | bool del(int data) 82 | { 83 | if (head == nullptr) 84 | { 85 | return true; 86 | } 87 | Node *p = head; 88 | while (p->next != nullptr) 89 | { 90 | p = p->next; 91 | if (p->next->data == data) 92 | { 93 | Node *tmp = p->next; 94 | p->next = p->next->next; 95 | delete tmp; 96 | return true; 97 | } 98 | } 99 | return false; 100 | } 101 | 102 | void print() 103 | { 104 | Node *p = head; 105 | while (p != nullptr) 106 | { 107 | cout << p->data << " "; 108 | p = p->next; 109 | } 110 | cout << endl; 111 | } 112 | }; 113 | 114 | int main(int argc, char const *argv[]) 115 | { 116 | LinkList l; 117 | // append random numbers 118 | vector numbers = {65, 89, 96, 16, 60, 43, 34, 20, 82}; 119 | for (int i = 0; i < numbers.size(); i++) 120 | { 121 | l.append(numbers[i]); 122 | } 123 | l.print(); 124 | 125 | // insert after 126 | cout << "insert 100 after 16: " << endl; 127 | cout << "before: "; 128 | l.print(); 129 | cout << "after: "; 130 | l.insert_after(16, 100); 131 | l.print(); 132 | 133 | // insert before 134 | cout << "insert 200 before 16: " << endl; 135 | cout << "before: "; 136 | l.print(); 137 | cout << "after: "; 138 | l.insert_before(16, 200); 139 | l.print(); 140 | 141 | // delete 142 | cout << "delete 20:" << endl; 143 | cout << "before: "; 144 | l.print(); 145 | cout << "after: "; 146 | l.del(20); 147 | l.print(); 148 | 149 | // append 150 | cout << "append 300:" << endl; 151 | cout << "before: "; 152 | l.print(); 153 | cout << "after: "; 154 | l.append(300); 155 | l.print(); 156 | return 0; 157 | } 158 | -------------------------------------------------------------------------------- /DataStructure/stack.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brian00715/PnC-Interview-Coding/af5170352673544e84492f908664d79f0aed5b25/DataStructure/stack.cc -------------------------------------------------------------------------------- /DoublePointer/11.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 11[M]. 盛最多水的容器 3 | * @details 4 | * @url https://leetcode.cn/problems/container-with-most-water/description/ 5 | * @idea 双指针,每次移动高度更小的柱子 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int maxArea(vector &height) 14 | { 15 | int n = height.size(); 16 | int left = 0, right = n - 1; 17 | int max_area = 0; 18 | while (left < right) 19 | { 20 | int area = min(height[left], height[right]) * (right - left); 21 | max_area = max(max_area, area); 22 | if (height[left] <= height[right]) { left++; } 23 | else { right--; } 24 | } 25 | return max_area; 26 | } 27 | }; 28 | 29 | int main(int argc, char const *argv[]) 30 | { 31 | Solution s; 32 | return 0; 33 | } -------------------------------------------------------------------------------- /DoublePointer/1100.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 1100[M]. 长度为 K 的无重复字符子串 3 | * @details 4 | * @url 5 | * https://leetcode.cn/problems/find-k-length-substrings-with-no-repeated-characters/description/ 6 | * @idea 双指针滑动窗口,用map统计出现频次,动态移动左右指针 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | public: 14 | int numKLenSubstrNoRepeats(string s, int k) 15 | { 16 | if (k > 26) { return 0; } 17 | int n = s.size(); 18 | unordered_map cnt; 19 | int left = 0, right = 0; 20 | int ans = 0; 21 | while (right <= n - 1) 22 | { 23 | cnt[s[right]]++; 24 | 25 | while (cnt[s[right]] > 1) 26 | { 27 | cnt[s[left]]--; 28 | left++; 29 | } 30 | 31 | if (right - left == k - 1) 32 | { 33 | ans++; 34 | cnt[s[left]]--; 35 | left++; 36 | } 37 | right++; 38 | } 39 | return ans; 40 | } 41 | }; 42 | 43 | int main(int argc, char const *argv[]) 44 | { 45 | Solution s; 46 | return 0; 47 | } -------------------------------------------------------------------------------- /DoublePointer/15.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 15.三数之和 3 | * @details 4 | * @url https://leetcode.cn/problems/3sum/description/ 5 | * @idea 核心思路是仍然是三重循环,但只枚举有序的三元组,并使用双指针避免重复枚举 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | vector> threeSum(vector &nums) 14 | { 15 | vector> rst; 16 | sort(nums.begin(), nums.end()); 17 | int n = nums.size(); 18 | 19 | for (int i = 0; i < n; i++) 20 | { 21 | // 跳过重复元素 22 | if (i > 0 && nums[i] == nums[i - 1]) continue; 23 | 24 | int left = i + 1; 25 | int right = n - 1; 26 | 27 | while (left < right) 28 | { 29 | int sum = nums[i] + nums[left] + nums[right]; 30 | 31 | if (sum == 0) 32 | { 33 | rst.push_back({nums[i], nums[left], nums[right]}); 34 | 35 | // 跳过重复元素 36 | while (left < right && nums[left] == nums[left + 1]) left++; 37 | while (left < right && nums[right] == nums[right - 1]) right--; 38 | 39 | left++; 40 | right--; 41 | } 42 | else if (sum < 0) { left++; } 43 | else { right--; } 44 | } 45 | } 46 | 47 | return rst; 48 | } 49 | }; 50 | 51 | int main(int argc, char const *argv[]) 52 | { 53 | Solution s; 54 | return 0; 55 | } -------------------------------------------------------------------------------- /DoublePointer/159.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 159[M]. 至多包含两个不同字符的最长子串 3 | * @details 4 | * @url https://leetcode.cn/problems/longest-substring-with-at-most-two-distinct-characters/ 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | class Solution 10 | { 11 | public: 12 | int lengthOfLongestSubstringTwoDistinct(string s) 13 | { 14 | int n = s.size(); 15 | if (n < 2) return 1; 16 | int left = 0, right = 0; 17 | int ans = 0; 18 | unordered_map hashmap; 19 | while (right < n) 20 | { 21 | hashmap[s[right]] = right; // 字符可能重复,存最右边的下标 22 | if (hashmap.size() == 3) 23 | { // 删除最左边的元素 24 | int del_idx = INT_MAX; 25 | for (auto &x : hashmap) 26 | { 27 | del_idx = min(del_idx, x.second); 28 | } 29 | hashmap.erase(s[del_idx]); 30 | left = del_idx + 1; 31 | } 32 | ans = max(ans, right - left + 1); 33 | right++; 34 | } 35 | return ans; 36 | } 37 | }; 38 | 39 | int main(int argc, char const *argv[]) 40 | { 41 | Solution s; 42 | return 0; 43 | } -------------------------------------------------------------------------------- /DoublePointer/3.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 3[M].无重复字符的最长子串 3 | * @details 4 | * @url https://leetcode.cn/problems/longest-substring-without-repeating-characters/ 5 | * @idea 双指针滑动窗口,迭代最大值 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int lengthOfLongestSubstring(string s) 14 | { 15 | int n = s.size(); 16 | if (n == 1) return 1; 17 | unordered_map hashmap; 18 | int left = 0, right = 0; 19 | int max_len = 0; 20 | while (right < n) 21 | { 22 | hashmap[s[right]]++; 23 | while (hashmap[s[right]] > 1) 24 | { 25 | hashmap[s[left]]--; 26 | left++; 27 | } 28 | max_len = max(max_len, right - left + 1); 29 | right++; 30 | } 31 | return max_len; 32 | } 33 | }; 34 | int main(int argc, char const *argv[]) 35 | { 36 | Solution s; 37 | return 0; 38 | } -------------------------------------------------------------------------------- /DoublePointer/340.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 340[M]. 至多包含 K 个不同字符的最长子串 3 | * @details 4 | * @url https://leetcode.cn/problems/longest-substring-with-at-most-k-distinct-characters/ 5 | * @idea 6 | * 滑动窗口,哈希表存每个字符最右边的下标,一旦窗口内有k+1个不同的字符就删除最左边的,迭代更新最大值 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | public: 14 | int lengthOfLongestSubstringKDistinct(string s, int k) 15 | { 16 | int n = s.size(); 17 | if (n < k) return n; 18 | int left = 0, right = 0; 19 | unordered_map hashmap; 20 | int max_len = 0; 21 | while (right < n) 22 | { 23 | hashmap[s[right]] = right; 24 | if (hashmap.size() == k + 1) 25 | { 26 | int del_idx = INT_MAX; 27 | for (auto &x : hashmap) 28 | { 29 | del_idx = min(del_idx, x.second); 30 | } 31 | hashmap.erase(s[del_idx]); 32 | left = del_idx + 1; 33 | } 34 | max_len = max(max_len, right - left + 1); 35 | right++; 36 | } 37 | return max_len; 38 | } 39 | }; 40 | 41 | int main(int argc, char const *argv[]) 42 | { 43 | Solution s; 44 | return 0; 45 | } -------------------------------------------------------------------------------- /DoublePointer/392.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 392.判断子序列 3 | * @details 4 | * @url https://leetcode.cn/problems/is-subsequence/description/ 5 | * @idea 贪心匹配+双指针,或者用二维dp向后递推dp[i][j]表示在目标串中从i向后字符j第一次出现的位置 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | bool isSubsequence(string s, string t) 14 | { 15 | int n1 = s.size(), n2 = t.size(); 16 | int i = 0, j = 0; 17 | while (i < n1 && j < n2) 18 | { 19 | if (s[i] == t[j]) { i++; } 20 | j++; 21 | } 22 | return i == n1; 23 | } 24 | }; 25 | 26 | int main(int argc, char const *argv[]) 27 | { 28 | Solution s; 29 | cout << s.isSubsequence("abc", "ahbgdc"); 30 | return 0; 31 | } -------------------------------------------------------------------------------- /DoublePointer/88.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 88.合并两个有序数组 3 | * @details 4 | * @url https://leetcode.cn/problems/merge-sorted-array/solutions/666608/he-bing-liang-ge-you-xu-shu-zu-by-leetco-rrb0/ 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | void merge(vector &nums1, int m, vector &nums2, int n) 14 | { 15 | int p1=m-1,p2=n-1; 16 | int tail = m+n-1; 17 | while(p1>=0 && p2>=0) 18 | { 19 | if(nums1[p1]>nums2[p2]) 20 | { 21 | nums1[tail--] = nums1[p1--]; 22 | } 23 | else if (nums1[p1]<=nums2[p2]) 24 | { 25 | nums1[tail--] = nums2[p2--]; 26 | } 27 | } 28 | if(p1==-1) 29 | { 30 | while(p2>=0) 31 | { 32 | nums1[tail--] = nums2[p2--]; 33 | } 34 | } 35 | else 36 | { 37 | while(p1>=0) 38 | { 39 | nums1[tail--] = nums1[p1--]; 40 | } 41 | } 42 | } 43 | }; 44 | 45 | int main(int argc, char const *argv[]) 46 | { 47 | Solution s; 48 | } -------------------------------------------------------------------------------- /Geometry/point_prejection.cc: -------------------------------------------------------------------------------- 1 | #include 2 | class Point 3 | { 4 | public: 5 | Point(double x, double y) : x(x), y(y) {} 6 | Point operator-(const Point &p) 7 | { 8 | return Point(x - p.x, y - p.y); 9 | } 10 | double operator*(const Point &p) 11 | { 12 | return x * p.x + y * p.y; 13 | } 14 | Point operator*(double a) 15 | { 16 | return Point(x * a, y * a); 17 | } 18 | Point operator+(const Point &p) 19 | { 20 | return Point(x + p.x, y + p.y); 21 | } 22 | double norm() 23 | { 24 | return sqrt(x * x + y * y); 25 | } 26 | 27 | Point operator/(double a) 28 | { 29 | return Point(x / a, y / a); 30 | } 31 | 32 | double x; 33 | double y; 34 | }; 35 | int main(int argc, char const *argv[]) 36 | { 37 | Point a(1, 1), b(2, 2), c(3, 3); 38 | Point ab = b - a; 39 | Point ac = c - a; 40 | double dot = ab * ac; 41 | Point map_vec = ab / ab.norm() * dot; 42 | Point map = a + map_vec; 43 | std::cout << map.x << " " << map.y << std::endl; 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /Geometry/point_triangle.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 判断点是否在三角形内 3 | * @details 4 | * @url 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int functionName() 14 | { 15 | return 0; 16 | } 17 | }; 18 | 19 | int main(int argc, char const *argv[]) 20 | { 21 | Solution s; 22 | } -------------------------------------------------------------------------------- /Graph/103.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 水流问题 3 | * @details 水流根据地形流向第一、第二边界,求第一、第二边界的水流量 4 | * @url https://kamacoder.com/problempage.php?pid=1175 5 | * @idea 6 | * @note 7 | */ 8 | // #include "../header.hpp" 9 | 10 | #include 11 | #include 12 | #include 13 | using namespace std; 14 | 15 | /*这种写法会导致内存超限,不知道为什么*/ 16 | class SolutionDeprecated 17 | { 18 | public: 19 | int dfs(vector> &map, int x, int y, vector> &visited) 20 | { 21 | if (visited[x][y] != 0) return visited[x][y]; 22 | 23 | if (x == 0 || y == 0) visited[x][y] = 1; 24 | if (x == map.size() - 1 || y == map[0].size() - 1) visited[x][y] = -1; 25 | 26 | const vector> dirs = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; 27 | unordered_set flag; 28 | for (auto &dir : dirs) 29 | { 30 | int next_x = x + dir[0], next_y = y + dir[1]; 31 | if (next_x < 0 || next_y < 0 || next_x >= map.size() || next_y >= map[0].size()) 32 | continue; 33 | 34 | auto next_height = map[next_x][next_y]; 35 | if (next_height > map[x][y]) continue; 36 | 37 | int rst = dfs(map, next_x, next_y, visited); 38 | flag.insert(rst); 39 | } 40 | 41 | if ((flag.count(1) && flag.count(-1)) || flag.count(2)) 42 | { 43 | visited[x][y] = 2; 44 | return 2; 45 | } 46 | if (flag.count(1)) 47 | { 48 | visited[x][y] = 1; 49 | return 1; 50 | } 51 | if (flag.count(-1)) 52 | { 53 | visited[x][y] = -1; 54 | return -1; 55 | } 56 | 57 | return 0; 58 | } 59 | 60 | void func(vector> &map, int m, int n) 61 | { 62 | vector> visited(m, vector(n, 0)); 63 | for (int i = 0; i < m; i++) 64 | { 65 | for (int j = 0; j < n; j++) 66 | { 67 | if (dfs(map, i, j, visited) == 2) cout << i << " " << j << endl; 68 | } 69 | } 70 | } 71 | }; 72 | 73 | /** 74 | * @brief 用两个visited数组分别从第一和第二边界出发找路,最后合并结果 75 | * 76 | */ 77 | class Solution 78 | { 79 | public: 80 | bool dfs(vector> &map, int x, int y, vector> &visited) 81 | { 82 | if (x < 0 || y < 0 || x > map.size() - 1 || y > map[0].size() - 1 || visited[x][y]) 83 | return false; 84 | visited[x][y] = true; 85 | const vector> dirs = { 86 | {0, -1}, 87 | {-1, 0}, 88 | {0, 1}, 89 | {1, 0}, 90 | }; 91 | for (auto &dir : dirs) 92 | { 93 | int new_x = x + dir[0], new_y = y + dir[1]; 94 | if (new_x < 0 || new_y < 0 || new_x > map.size() - 1 || new_y > map[0].size() - 1) 95 | continue; 96 | 97 | int new_h = map[new_x][new_y]; 98 | if (new_h < map[x][y]) continue; // from low to high 99 | 100 | dfs(map, new_x, new_y, visited); 101 | } 102 | return true; 103 | } 104 | 105 | void func(vector> map, int m, int n) 106 | { 107 | vector> visiteed_lu(m, vector(n, false)); 108 | vector> visiteed_rd(m, vector(n, false)); 109 | 110 | for (int i = 0; i < m; i++) 111 | { 112 | dfs(map, i, 0, visiteed_lu); 113 | dfs(map, i, n - 1, visiteed_rd); 114 | } 115 | 116 | for (int i = 0; i < n; i++) 117 | { 118 | dfs(map, 0, i, visiteed_lu); 119 | dfs(map, m - 1, i, visiteed_rd); 120 | } 121 | 122 | for (int i = 0; i < m; i++) 123 | { 124 | for (int j = 0; j < n; j++) 125 | { 126 | if (visiteed_lu[i][j] && visiteed_rd[i][j]) { cout << i << " " << j << endl; } 127 | } 128 | } 129 | } 130 | }; 131 | 132 | int main(int argc, char const *argv[]) 133 | { 134 | #define TWO 135 | 136 | #ifdef ONE 137 | vector> map = { 138 | {1, 3, 1, 2, 4}, {1, 2, 1, 3, 2}, {2, 4, 7, 2, 1}, {4, 5, 6, 1, 1}, {1, 4, 1, 2, 1}, 139 | }; 140 | int m = map.size(), n = map[0].size(); 141 | #endif 142 | 143 | #ifdef TWO 144 | int m, n; 145 | cin >> m >> n; 146 | vector> map(m, vector(n)); 147 | for (int i = 0; i < m; i++) 148 | { 149 | for (int j = 0; j < n; j++) 150 | { 151 | int tmp; 152 | cin >> tmp; 153 | map[i][j] = tmp; 154 | } 155 | } 156 | 157 | #endif 158 | 159 | Solution s; 160 | s.func(map, m, n); 161 | return 0; 162 | } -------------------------------------------------------------------------------- /Graph/200.cc: -------------------------------------------------------------------------------- 1 | /** https://leetcode.cn/problems/number-of-islands/ 2 | * 给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。 3 | 4 | 岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 5 | 6 | 此外,你可以假设该网格的四条边均被水包围。 7 | 8 | */ 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | public: 14 | int numIslands(vector> &grid) 15 | { 16 | int num = 0; 17 | vector> grid_copy(grid); 18 | 19 | for (int i = 0; i < grid.size(); i++) 20 | { 21 | for (int j = 0; j < grid[i].size(); j++) 22 | { 23 | if (grid[i][j] == '1') // not been visited and is a piece of land 24 | { 25 | num++; 26 | // dfs(grid, i, j); // traverse the connected area and mark them as visited 27 | bfs(grid, i, j); 28 | } 29 | } 30 | } 31 | return num; 32 | } 33 | 34 | /** 35 | * @param x,y the index of grid array 36 | */ 37 | void dfs(vector> &grid, int r, int c) 38 | { 39 | if (r < 0 || r >= grid.size() || c < 0 || c >= grid[0].size() || 40 | grid[r][c] != '1') // exceed the boundary or been visited or not land 41 | return; 42 | grid[r][c] = '2'; 43 | dfs(grid, r - 1, c); 44 | dfs(grid, r + 1, c); 45 | dfs(grid, r, c - 1); 46 | dfs(grid, r, c + 1); 47 | } 48 | 49 | void bfs(vector> &grid, int r, int c) 50 | { 51 | queue> q; 52 | q.push({r, c}); 53 | grid[r][c] = '2'; 54 | while (!q.empty()) 55 | { 56 | auto [x, y] = q.front(); 57 | q.pop(); 58 | // traverse the four directions 59 | for (auto &d : directions) 60 | { 61 | int new_x = x + d[0]; 62 | int new_y = y + d[1]; 63 | if (new_x >= 0 && new_x < grid.size() && new_y >= 0 && new_y < grid[0].size() && 64 | grid[new_x][new_y] == '1') 65 | { 66 | grid[new_x][new_y] = '2'; 67 | q.push({new_x, new_y}); 68 | } 69 | } 70 | } 71 | } 72 | 73 | private: 74 | vector> directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; 75 | }; 76 | 77 | int main() 78 | { 79 | Solution s; 80 | vector> grid1 = {{'1', '1', '1', '1', '0'}, 81 | {'1', '1', '0', '1', '0'}, 82 | {'1', '1', '0', '0', '0'}, 83 | {'0', '0', '0', '0', '0'}}; 84 | vector> grid2 = {{'1', '1', '0', '0', '0'}, 85 | {'1', '1', '0', '0', '0'}, 86 | {'0', '0', '1', '0', '0'}, 87 | {'0', '0', '0', '1', '1'}}; 88 | vector> grid3 = {{'1', '1', '1'}, {'0', '1', '0'}, {'1', '1', '1'}}; 89 | vector> grid4 = {{'1', '1'}}; 90 | cout << s.numIslands(grid2) << endl; 91 | } -------------------------------------------------------------------------------- /Graph/2290.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 2290[H].到达角落需要移除障碍物的最小数目 3 | * @details 4 | * @url https://leetcode.cn/problems/minimum-obstacle-removal-to-reach-corner/ 5 | * @idea 把所有路都视为可通行的,障碍物视为代价,bfs搜索。注意用标记visited避免超时 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | // Dijkstra 11 | class Solution 12 | { 13 | vector> dirs = { 14 | {-1, 0}, 15 | {0, -1}, 16 | {1, 0}, 17 | {0, 1}, 18 | }; 19 | 20 | public: 21 | int minimumObstacles(vector> &grid) 22 | { 23 | int m = grid.size(), n = grid[0].size(); 24 | auto cmp = [](tuple node1, tuple node2) { 25 | return get<2>(node1) > get<2>(node2); 26 | }; 27 | priority_queue, vector>, 28 | function, tuple)>> 29 | open_list(cmp); 30 | vector> visited(m, vector(n, INT_MAX)); // 如果不加visited会超时 31 | visited[0][0] = 0; 32 | 33 | open_list.emplace(0, 0, 0); 34 | while (!open_list.empty()) 35 | { 36 | auto [x, y, cost] = open_list.top(); 37 | if (x == m - 1 && y == n - 1) { return cost; } 38 | open_list.pop(); 39 | for (auto &dir : dirs) 40 | { 41 | int new_x = x + dir[0]; 42 | int new_y = y + dir[1]; 43 | if (new_x < 0 || new_x > m - 1 || new_y < 0 || new_y > n - 1) { continue; } 44 | int new_cost = grid[new_x][new_y] + cost; 45 | if (new_cost < visited[new_x][new_y]) 46 | { 47 | open_list.emplace(new_x, new_y, new_cost); 48 | visited[new_x][new_y] = new_cost; 49 | } 50 | } 51 | } 52 | return -1; 53 | } 54 | }; 55 | 56 | // 0-1 BFS优化耗时 57 | class Solution2 58 | { 59 | vector> dirs = { 60 | {-1, 0}, 61 | {0, -1}, 62 | {1, 0}, 63 | {0, 1}, 64 | }; 65 | 66 | public: 67 | int minimumObstacles(vector> &grid) 68 | { 69 | int m = grid.size(), n = grid[0].size(); 70 | deque> dq; 71 | vector> visited(m, vector(n, INT_MAX)); 72 | visited[0][0] = 0; 73 | 74 | dq.emplace_front(0, 0, 0); // 起点入队,代价为0 75 | 76 | while (!dq.empty()) 77 | { 78 | auto [x, y, cost] = dq.front(); 79 | dq.pop_front(); 80 | 81 | if (x == m - 1 && y == n - 1) { return cost; } 82 | 83 | for (auto &dir : dirs) 84 | { 85 | int new_x = x + dir[0]; 86 | int new_y = y + dir[1]; 87 | if (new_x < 0 || new_x >= m || new_y < 0 || new_y >= n) { continue; } 88 | 89 | int new_cost = cost + grid[new_x][new_y]; 90 | if (new_cost < visited[new_x][new_y]) 91 | { 92 | visited[new_x][new_y] = new_cost; 93 | if (grid[new_x][new_y] == 0) 94 | { 95 | dq.emplace_front(new_x, new_y, new_cost); // 如果代价为0,优先处理 96 | } 97 | else 98 | { 99 | dq.emplace_back(new_x, new_y, new_cost); // 代价为1的放在队列后面 100 | } 101 | } 102 | } 103 | } 104 | 105 | return -1; // 理论上不会到达这里 106 | } 107 | }; 108 | 109 | int main(int argc, char const *argv[]) 110 | { 111 | Solution s; 112 | return 0; 113 | } -------------------------------------------------------------------------------- /Graph/2685.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | class Solution 8 | { 9 | public: 10 | int countCompleteComponents(int n, vector> &edges) 11 | { 12 | // 使用度和邻居集合来判断连通分量 13 | vector degree(n, 0); 14 | vector> neighbors(n); 15 | 16 | // 记录每个节点的度数和邻居 17 | for (const auto &edge : edges) 18 | { 19 | int u = edge[0], v = edge[1]; 20 | degree[u]++; 21 | degree[v]++; 22 | neighbors[u].insert(v); 23 | neighbors[v].insert(u); 24 | } 25 | 26 | // 找到每个连通分量并判断是否是完全连通分量 27 | vector visited(n, false); 28 | int completeComponents = 0; 29 | 30 | for (int i = 0; i < n; ++i) 31 | { 32 | if (!visited[i]) 33 | { 34 | unordered_set componentNodes; 35 | findComponent(i, neighbors, visited, componentNodes); 36 | 37 | // 判断该连通分量是否是完全连通的 38 | bool isComplete = true; 39 | for (int node : componentNodes) 40 | { 41 | // 如果度数不等于组件大小 - 1 或者邻居不是整个集合,说明不是完全连通分量 42 | if (degree[node] != componentNodes.size() - 1) 43 | { 44 | isComplete = false; 45 | break; 46 | } 47 | } 48 | if (isComplete) { completeComponents++; } 49 | } 50 | } 51 | 52 | return completeComponents; 53 | } 54 | 55 | private: 56 | void findComponent(int node, const vector> &neighbors, vector &visited, 57 | unordered_set &componentNodes) 58 | { 59 | visited[node] = true; 60 | componentNodes.insert(node); 61 | for (int neighbor : neighbors[node]) 62 | { 63 | if (!visited[neighbor]) { findComponent(neighbor, neighbors, visited, componentNodes); } 64 | } 65 | } 66 | }; 67 | -------------------------------------------------------------------------------- /Graph/417.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brian00715/PnC-Interview-Coding/af5170352673544e84492f908664d79f0aed5b25/Graph/417.cc -------------------------------------------------------------------------------- /Graph/695.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 695.最大岛屿面积 3 | * @details 4 | * @url https://leetcode.cn/problems/max-area-of-island/description/ 5 | * @idea 6 | * 1. 递归式DFS 7 | * 2. 栈式DFS 8 | * 3. BFS 9 | * @note 10 | */ 11 | #include "../header.hpp" 12 | 13 | class Solution 14 | { 15 | public: 16 | int maxAreaOfIsland(vector> &grid) 17 | { 18 | int max_area = -1; 19 | for (int i = 0; i < grid.size(); i++) 20 | { 21 | for (int j = 0; j < grid[0].size(); j++) 22 | { 23 | max_area = max(max_area, dfs(grid, i, j)); 24 | } 25 | } 26 | return max_area; 27 | } 28 | 29 | int dfs(vector> &grid, int x, int y) 30 | { 31 | if (x == grid.size() || x < 0 || y == grid[0].size() || y < 0 || grid[x][y] != 1) 32 | { 33 | return 0; 34 | } 35 | grid[x][y] = 2; 36 | int area = 1; 37 | area += dfs(grid, x - 1, y); 38 | area += dfs(grid, x, y - 1); 39 | area += dfs(grid, x + 1, y); 40 | area += dfs(grid, x, y + 1); 41 | return area; 42 | } 43 | }; 44 | 45 | int main(int argc, char const *argv[]) 46 | { 47 | Solution s; 48 | vector> input{ 49 | {0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0}, 50 | {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0}, 51 | {0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0}, 52 | {0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0}, 53 | {0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0}, 54 | {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0}, 55 | {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0}, 56 | {0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0}}; 57 | int max_area = s.maxAreaOfIsland(input); 58 | printf("max area is:%d\r\n", max_area); 59 | } -------------------------------------------------------------------------------- /Graph/797.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 给你一个有 n 个节点的 有向无环图(DAG),请你找出所有从节点 0 到节点 n-1 的路径并输出(不要求按特定顺序) 3 | graph[i] 是一个从节点 i 可以访问的所有节点的列表(即从节点 i 到节点 graph[i][j]存在一条有向边)。 4 | https://leetcode.cn/problems/all-paths-from-source-to-target/description/ 5 | */ 6 | 7 | #include "../header.hpp" 8 | 9 | class Solution 10 | { 11 | public: 12 | vector> allPathsSourceTarget(vector> &graph) 13 | { 14 | path.push_back(0); // start from node 0 15 | dfs(graph, 0); 16 | return res; 17 | } 18 | 19 | /** 20 | * @param path current path 21 | * @param res all paths 22 | */ 23 | void dfs(vector> &graph, int start) 24 | { 25 | if (start == graph.size() - 1) // reach the end 26 | { 27 | res.push_back(path); 28 | return; 29 | } 30 | for (int i = 0; i < graph[start].size(); i++) // traverse all the adjecent nodes 31 | { 32 | path.push_back(graph[start][i]); 33 | dfs(graph, graph[start][i]); // find the path from current node to the end 34 | path.pop_back(); // backtracking. pop the current node to gurantee other recursions use the indipendent path variable 35 | } 36 | } 37 | 38 | void printAllPaths() 39 | { 40 | for (int i = 0; i < res.size(); i++) 41 | { 42 | cout << "path " << i << ": "; 43 | for (int j = 0; j < res[i].size(); j++) 44 | { 45 | cout << res[i][j] << " "; 46 | } 47 | cout << "------" << endl; 48 | } 49 | } 50 | 51 | private: 52 | vector path; // current path 53 | vector> res; // all paths 54 | }; 55 | 56 | int main(int argc, char const *argv[]) 57 | { 58 | vector> graph = {{1, 2}, {3}, {3}, {}}; // means the adjacent nodes of each node 59 | Solution s; 60 | vector> res = s.allPathsSourceTarget(graph); 61 | for (int i = 0; i < res.size(); i++) 62 | { 63 | for (int j = 0; j < res[i].size(); j++) 64 | { 65 | cout << res[i][j] << " "; 66 | } 67 | cout << endl; 68 | } 69 | return 0; 70 | } 71 | -------------------------------------------------------------------------------- /Graph/815.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 815.公交线路 3 | * @details 4 | * @url https://leetcode.cn/problems/bus-routes/description/ 5 | * @idea 建图+BFS搜索 6 | * 用unordered_map维护每个站点包含的线路,队列维护遍历的站点。如何保证最短?因为BFS是逐层遍历,因此找到的就是最短的 7 | * https://leetcode.cn/problems/bus-routes/solutions/1814176/luo-by-jefff-r7i0/ 8 | * @note 遍历顺序:对于当前节点,遍历所有节点所在的路线,再针对每一条路线遍历每一个新站点 9 | */ 10 | #include "../header.hpp" 11 | 12 | class Solution 13 | { 14 | public: 15 | int numBusesToDestination(vector> &routes, int source, int target) 16 | { 17 | if (source == target) 18 | return 0; 19 | // build grph 20 | unordered_map> site_route; // stores the routes inluded by every site 21 | for (int i = 0; i < routes.size(); i++) 22 | { 23 | for (auto site : routes[i]) 24 | { 25 | site_route[site].push_back(i); 26 | } 27 | } 28 | 29 | // search the path 30 | queue q; // stores sites to be traversed 31 | vector visited(routes.size(), false); // whether a route has been visited 32 | q.push(source); 33 | int length = 0; // routes(bus) number 34 | while (!q.empty()) 35 | { 36 | length++; 37 | int size = q.size(); // NOTE: size must be acquired out of the loop below, because q.size() will change inside the loop 38 | for (int i = 0; i < size; i++) // traverse all nodes in queue at a time, which means 39 | { 40 | int curr_site = q.front(); 41 | q.pop(); 42 | for (auto &route : site_route[curr_site]) // traverse all possible routes from current site to target 43 | { 44 | if (!visited[route]) 45 | { 46 | visited[route] = true; 47 | for (auto site : routes[route]) // next site to be visited 48 | { 49 | if (site == target) 50 | { 51 | return length; 52 | } 53 | q.push(site); 54 | } 55 | } 56 | } 57 | } 58 | } 59 | 60 | return -1; 61 | } 62 | }; 63 | 64 | int main(int argc, char const *argv[]) 65 | { 66 | Solution s; 67 | } -------------------------------------------------------------------------------- /Graph/827.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 827[H]. 最大人工岛/Kama 104 3 | * @details 4 | * @url https://kamacoder.com/problempage.php?pid=1176 5 | * @idea 两次遍历,第一次标记岛屿并用map维护面积;第二次用每个cell尝试拼接岛屿 6 | * @note 7 | */ 8 | // #include "../header.hpp" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | using namespace std; 15 | 16 | class Solution 17 | { 18 | public: 19 | int dfs(vector> &map, int x, int y, int flag) 20 | { 21 | if (x < 0 || y < 0 || x > map.size() - 1 || y > map[0].size() - 1 || map[x][y] != 1) 22 | return 0; 23 | 24 | map[x][y] = flag; 25 | int size = 1; 26 | size += dfs(map, x - 1, y, flag); 27 | size += dfs(map, x, y - 1, flag); 28 | size += dfs(map, x + 1, y, flag); 29 | size += dfs(map, x, y + 1, flag); 30 | return size; 31 | } 32 | 33 | int func(vector> &grid, int m, int n) 34 | { 35 | int flag = 2; 36 | unordered_map map_size; 37 | for (int i = 0; i < m; i++) 38 | { 39 | for (int j = 0; j < n; j++) 40 | { 41 | if (grid[i][j] == 1) 42 | { 43 | int size = dfs(grid, i, j, flag); 44 | map_size.insert({flag, size}); 45 | flag++; 46 | } 47 | } 48 | } 49 | // PrintVector(grid); 50 | 51 | int max_size = 1; 52 | vector> dirs = { 53 | {-1, 0}, 54 | {1, 0}, 55 | {0, 1}, 56 | {0, -1}, 57 | }; 58 | for (int i = 0; i < m; i++) 59 | { 60 | for (int j = 0; j < n; j++) 61 | { 62 | int flag = grid[i][j]; 63 | int curr_size = map_size[flag]; 64 | if (grid[i][j] == 0) 65 | { 66 | int curr_max_size = 1; 67 | unordered_set neigh_flag; 68 | for (auto &dir : dirs) // check neighbors 69 | { 70 | int new_x = i + dir[0], new_y = j + dir[1]; 71 | if (new_x < 0 || new_y < 0 || new_x > grid.size() - 1 || 72 | new_y > grid[0].size() - 1) 73 | continue; 74 | 75 | if (grid[new_x][new_y] != 0) 76 | { 77 | int flag = grid[new_x][new_y]; 78 | // NOTE: very important to prevent duplicated count! 79 | if (neigh_flag.count(flag) == 0) { curr_max_size += map_size[flag]; } 80 | neigh_flag.insert(flag); 81 | } 82 | } 83 | max_size = std::max(max_size, curr_max_size); 84 | } 85 | max_size = max(max_size, curr_size); 86 | } 87 | } 88 | return max_size; 89 | } 90 | }; 91 | 92 | int main(int argc, char const *argv[]) 93 | { 94 | #define TWO 95 | #ifdef ONE 96 | vector> map = { 97 | {1, 1, 0, 0, 0}, 98 | {1, 1, 0, 0, 0}, 99 | {0, 0, 1, 0, 0}, 100 | {0, 0, 0, 1, 1}, 101 | }; 102 | int m = map.size(), n = map[0].size() - 1; 103 | #endif 104 | 105 | #ifdef TWO 106 | int m, n; 107 | cin >> m >> n; 108 | vector> map(m, vector(n, 0)); 109 | for (int i = 0; i < m; i++) 110 | { 111 | for (int j = 0; j < n; j++) { cin >> map[i][j]; } 112 | } 113 | #endif 114 | 115 | Solution s; 116 | int max_size = s.func(map, m, n); 117 | cout << max_size; 118 | } -------------------------------------------------------------------------------- /Graph/all_possible_paths_with_weight.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 输入带权重的有向无环图,找出从start到end的所有路径,并按照权重从小到大排序 3 | */ 4 | 5 | #include "../header.hpp" 6 | 7 | class Solution 8 | { 9 | public: 10 | Solution(vector> &input) 11 | { 12 | auto lastItem = input.back(); 13 | vertexNum = lastItem[0]; 14 | graph = new vector>(vertexNum, vector(vertexNum, 0)); 15 | for (int i = 0; i < input.size(); i++) 16 | { 17 | (*graph)[input[i][0] - 1][input[i][1] - 1] = input[i][2]; 18 | } 19 | printGraph(); 20 | } 21 | vector> allPathsSourceTarget(int start, int end) 22 | { 23 | path.push_back(0); // start from node 0 24 | dfs(start, end); 25 | return res; 26 | } 27 | 28 | /** 29 | * @param path current path 30 | * @param res all paths 31 | */ 32 | void dfs(int start, int end) 33 | { 34 | if (start == end) // reach the end 35 | { 36 | res.push_back(path); 37 | weights.push_back(weight); 38 | return; 39 | } 40 | for (int i = 0; i < vertexNum; i++) // traverse all the adjecent nodes 41 | { 42 | if ((*graph)[start][i] == 0) 43 | continue; 44 | path.push_back(i); 45 | weight += (*graph)[start][i]; 46 | dfs(i, end); // find the path from current node to the end 47 | path.pop_back(); // backtracking. pop the current node to gurantee other recursions use the indipendent path variable 48 | weight -= (*graph)[start][i]; 49 | } 50 | } 51 | 52 | void printAllPaths() 53 | { 54 | for (int i = 0; i < res.size(); i++) 55 | { 56 | cout << "path " << i << ": "; 57 | for (int j = 0; j < res[i].size(); j++) 58 | { 59 | cout << res[i][j] << " "; 60 | } 61 | cout << " weight: " << weights[i] << endl; // print the weight of each path 62 | cout << "------" << endl; 63 | } 64 | } 65 | 66 | void printGraph() 67 | { 68 | for (int i = 0; i < graph->size(); i++) 69 | { 70 | for (int j = 0; j < (*graph)[i].size(); j++) 71 | { 72 | cout << (*graph)[i][j] << " "; 73 | } 74 | cout << endl; 75 | } 76 | } 77 | 78 | vector> res; // all paths 79 | vector weights; // all paths' weights 80 | private: 81 | vector> *graph; 82 | vector path; // current path 83 | int weight = 0; // current path weight 84 | int vertexNum; 85 | }; 86 | 87 | int main(int argc, char const *argv[]) 88 | { 89 | // [[1,2,3],[1,3,2],[1,4,1],[2,5,2],[3,6,1],[4,6,4],[4,5,3],[6,5,3]] 90 | vector> input = { 91 | {1, 2, 3}, 92 | {1, 3, 2}, 93 | {1, 4, 1}, 94 | {2, 5, 2}, 95 | {3, 6, 1}, 96 | {4, 6, 4}, 97 | {4, 5, 3}, 98 | {6, 5, 3}, 99 | }; 100 | 101 | Solution s(input); 102 | vector> res = s.allPathsSourceTarget(0, 4); 103 | vector weights(s.weights); 104 | 105 | cout << "all paths: " << endl; 106 | for (int i = 0; i < res.size(); i++) 107 | { 108 | for (int j = 0; j < res[i].size(); j++) 109 | { 110 | cout << res[i][j] + 1 << " "; 111 | } 112 | cout << " weight: " << s.weights[i] << endl; 113 | } 114 | 115 | vector flag; 116 | for (int i = 0; i < res.size(); i++) 117 | { 118 | flag.push_back(i); 119 | } 120 | std::sort(flag.begin(), flag.end(), 121 | [&res, &weights](int a, int b) 122 | { 123 | return weights[a] < weights[b]; 124 | }); 125 | cout << "sorted paths: " << endl; 126 | for (int i = 0; i < flag.size(); i++) 127 | { 128 | for (int j = 0; j < res[flag[i]].size(); j++) 129 | { 130 | cout << res[flag[i]][j] + 1 << " "; 131 | } 132 | cout << " weight: " << weights[flag[i]] << endl; 133 | } 134 | return 0; 135 | } 136 | -------------------------------------------------------------------------------- /Greedy/45.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brian00715/PnC-Interview-Coding/af5170352673544e84492f908664d79f0aed5b25/Greedy/45.cc -------------------------------------------------------------------------------- /Greedy/55.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 55. 跳跃游戏 3 | * @details 4 | * @url https://leetcode.cn/problems/jump-game/description/ 5 | * @idea 贪心法,每次尽可能跳的多就行 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | bool canJump(vector& nums) { 14 | 15 | } 16 | }; 17 | 18 | int main(int argc, char const *argv[]) 19 | { 20 | Solution s; 21 | } -------------------------------------------------------------------------------- /Greedy/860.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 860.柠檬水找零 3 | * @details 4 | * @url https://leetcode.cn/problems/lemonade-change/description/ 5 | * @idea 贪心+分类讨论 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | bool lemonadeChange(vector &bills) 14 | { 15 | int five = 0, ten = 0; // number of cash we have 16 | for (auto bill : bills) 17 | { 18 | if (bill == 5) // don't need to change 19 | { 20 | five++; 21 | } 22 | else if (bill == 10) 23 | { 24 | if (five == 0) 25 | { 26 | return false; 27 | } 28 | five--; 29 | ten++; 30 | } 31 | else // 20 32 | { 33 | // there's two kinds of combination to change: 10+5 or 5x3 34 | if (ten > 0 && five > 0) 35 | { 36 | ten--; 37 | five--; 38 | } 39 | else if (five >= 3) 40 | { 41 | five -= 3; 42 | } 43 | else 44 | { 45 | return false; 46 | } 47 | } 48 | } 49 | return true; 50 | } 51 | }; 52 | 53 | int main(int argc, char const *argv[]) 54 | { 55 | Solution s; 56 | vector input{ 57 | 5, 5, 5, 10, 20}; 58 | bool rst = s.lemonadeChange(input); 59 | cout << (rst ? "true" : "false") << endl; 60 | } -------------------------------------------------------------------------------- /HashTable/1.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 1. 两数之和 3 | * @details 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。 4 | 5 | 你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。 6 | 7 | 你可以按任意顺序返回答案。 8 | * @url https://leetcode.cn/problems/two-sum/description/ 9 | * @idea 两层for或者哈希表 10 | * @note 11 | */ 12 | #include "../header.hpp" 13 | 14 | class Solution 15 | { 16 | public: 17 | vector twoSum(vector &nums, int target) 18 | { 19 | unordered_map hash; 20 | for (int i = 0; i < nums.size(); i++) 21 | { 22 | auto it = hash.find(target - nums[i]); 23 | if (it != hash.end()) 24 | { 25 | return {it->second, i}; 26 | } 27 | 28 | hash.insert({nums[i], i}); 29 | } 30 | return {}; 31 | } 32 | }; 33 | 34 | int main(int argc, char const *argv[]) 35 | { 36 | Solution s; 37 | vector input = {2, 7, 11, 15}; 38 | vector rst = s.twoSum(input, 9); 39 | for (auto x : rst) 40 | { 41 | cout << x << " "; 42 | } 43 | } -------------------------------------------------------------------------------- /HashTable/128.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 128. 最长连续子序列 3 | * @details 给定一个未排序的整数数组 nums 4 | ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。 5 | 请你设计并实现时间复杂度为 O(n) 的算法解决此问题 6 | * @url 7 | https://leetcode.cn/problems/longest-consecutive-sequence/description/?envType=study-plan-v2&envId=top-100-liked 8 | * @idea 哈希表 9 | * @note 10 | */ 11 | #include "../header.hpp" 12 | 13 | class Solution 14 | { 15 | public: 16 | int longestConsecutive(vector &nums) 17 | { 18 | // build a set 19 | unordered_set hash; 20 | for (auto x : nums) { hash.insert(x); } 21 | 22 | int max_length = 0; 23 | for (int i = 0; i < nums.size(); i++) 24 | { 25 | int curr_num = nums[i]; 26 | int length = 1; 27 | if (!hash.count(curr_num - 1)) 28 | { 29 | while (hash.count(curr_num + 1)) 30 | { 31 | curr_num += 1; 32 | length += 1; 33 | } 34 | if (length > max_length) { max_length = length; } 35 | } 36 | } 37 | return max_length; 38 | } 39 | }; 40 | 41 | int main(int argc, char const *argv[]) { Solution s; } -------------------------------------------------------------------------------- /LinkList/141.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 141.环形链表 3 | * @details 判断链表内是否有环 4 | * @url https://leetcode.cn/problems/linked-list-cycle/description/ 5 | * @idea 构建哈希表记录遍历时是否访问过某个相同的节点,若访问过则表明出现了环 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | bool hasCycle(ListNode *head) 14 | { 15 | if (head == nullptr) return false; 16 | unordered_set visited; 17 | ListNode *curr_ptr = head; 18 | while (curr_ptr != nullptr) 19 | { 20 | if (visited.count(curr_ptr)) { return true; } 21 | visited.insert(curr_ptr); 22 | curr_ptr = curr_ptr->next; 23 | } 24 | return false; 25 | } 26 | }; 27 | 28 | int main() 29 | { 30 | Solution solution; 31 | 32 | // Test case 1: 无环链表 33 | ListNode *head1 = new ListNode(1); 34 | head1->next = new ListNode(2); 35 | head1->next->next = new ListNode(3); 36 | cout << "Test case 1: " << (solution.hasCycle(head1) ? "Cycle detected" : "No cycle") 37 | << endl; // 应输出 "No cycle" 38 | 39 | // Test case 2: 有环链表 40 | ListNode *head2 = new ListNode(1); 41 | head2->next = new ListNode(2); 42 | head2->next->next = new ListNode(3); 43 | head2->next->next->next = head2->next; // 3 -> 2 形成环 44 | cout << "Test case 2: " << (solution.hasCycle(head2) ? "Cycle detected" : "No cycle") 45 | << endl; // 应输出 "Cycle detected" 46 | 47 | // Test case 3: 单个节点无环 48 | ListNode *head3 = new ListNode(1); 49 | cout << "Test case 3: " << (solution.hasCycle(head3) ? "Cycle detected" : "No cycle") 50 | << endl; // 应输出 "No cycle" 51 | 52 | // Test case 4: 单个节点自环 53 | ListNode *head4 = new ListNode(1); 54 | head4->next = head4; // 自环 55 | cout << "Test case 4: " << (solution.hasCycle(head4) ? "Cycle detected" : "No cycle") 56 | << endl; // 应输出 "Cycle detected" 57 | 58 | // Test case 5: 空链表 59 | ListNode *head5 = nullptr; 60 | cout << "Test case 5: " << (solution.hasCycle(head5) ? "Cycle detected" : "No cycle") 61 | << endl; // 应输出 "No cycle" 62 | 63 | return 0; 64 | } -------------------------------------------------------------------------------- /LinkList/147.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 147.对链表进行插入排序 3 | * @details 4 | * @url https://leetcode.cn/problems/insertion-sort-list/description/ 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | /** 11 | * Definition for singly-linked list. 12 | * struct ListNode { 13 | * int val; 14 | * ListNode *next; 15 | * ListNode() : val(0), next(nullptr) {} 16 | * ListNode(int x) : val(x), next(nullptr) {} 17 | * ListNode(int x, ListNode *next) : val(x), next(next) {} 18 | * }; 19 | */ 20 | class Solution 21 | { 22 | public: 23 | ListNode *insertionSortList(ListNode *head) 24 | { 25 | if (!head) return nullptr; 26 | 27 | ListNode dummy; 28 | dummy.next = head; 29 | ListNode *curr = head->next; // start from 2nd node 30 | ListNode *last_sorted = head; 31 | while (curr) 32 | { 33 | if (curr->val >= last_sorted->val) { last_sorted = last_sorted->next; } 34 | else 35 | { 36 | ListNode *prev = &dummy; 37 | while (curr->val >= prev->next->val) // find the suitable insertion pos 38 | { 39 | prev = prev->next; 40 | } 41 | // execute insertion 42 | last_sorted->next = curr->next; // NOTE: may be hard to remember 43 | curr->next = prev->next; 44 | prev->next = curr; 45 | } 46 | curr = last_sorted->next; 47 | } 48 | return dummy.next; 49 | } 50 | }; 51 | 52 | int main(int argc, char const *argv[]) 53 | { 54 | Solution s; 55 | vector data = {-1, 5, 3, 4, 0}; 56 | ListNode list1(data); 57 | list1.printList(); 58 | auto sorted = s.insertionSortList(&list1); 59 | sorted->printList(); 60 | return 0; 61 | } -------------------------------------------------------------------------------- /LinkList/148.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 148.排序链表 3 | * @details 4 | * @url https://leetcode.cn/problems/sort-list/description/ 5 | * @idea 归并排序,用快慢指针找中点,递归调用,写辅助链表合并函数 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | /** 11 | * Definition for singly-linked list. 12 | * struct ListNode { 13 | * int val; 14 | * ListNode *next; 15 | * ListNode() : val(0), next(nullptr) {} 16 | * ListNode(int x) : val(x), next(nullptr) {} 17 | * ListNode(int x, ListNode *next) : val(x), next(next) {} 18 | * }; 19 | */ 20 | class Solution 21 | { 22 | public: 23 | ListNode *sortList(ListNode *head) 24 | { 25 | return recursiveSortList(head, nullptr); 26 | } 27 | 28 | ListNode *recursiveSortList(ListNode *head, ListNode *tail) 29 | { 30 | if (head == nullptr) return nullptr; 31 | if (head->next == tail) // only two nodes 32 | { 33 | head->next = nullptr; 34 | return head; 35 | } 36 | ListNode *fast = head; 37 | ListNode *slow = head; 38 | int cnt = 0; 39 | while (fast != tail) 40 | { 41 | // NOTE: The following block is much slower 42 | // fast = fast->next; 43 | // if (cnt % 2 == 0) 44 | // { 45 | // slow = slow->next; 46 | // cnt++; 47 | // } 48 | 49 | slow = slow->next; 50 | fast = fast->next; 51 | if (fast != tail) { fast = fast->next; } 52 | } 53 | ListNode *rst = mergeSorted(recursiveSortList(head, slow), recursiveSortList(slow, tail)); 54 | return rst; 55 | } 56 | 57 | ListNode *mergeSorted(ListNode *l1, ListNode *l2) 58 | { 59 | ListNode merged; 60 | ListNode *curr1 = l1, *curr2 = l2; 61 | ListNode *curr_merge = &merged; 62 | while (curr1 != nullptr && curr2 != nullptr) 63 | { 64 | if (curr1->val < curr2->val) 65 | { 66 | curr_merge->next = curr1; 67 | curr_merge = curr1; 68 | curr1 = curr1->next; 69 | } 70 | else 71 | { 72 | curr_merge->next = curr2; 73 | curr_merge = curr2; 74 | curr2 = curr2->next; 75 | } 76 | } 77 | if (curr1) { curr_merge->next = curr1; } 78 | else { curr_merge->next = curr2; } 79 | return merged.next; 80 | } 81 | }; 82 | 83 | int main(int argc, char const *argv[]) 84 | { 85 | Solution s; 86 | vector data = {-1, 5, 3, 4, 0}; 87 | ListNode list1(data); 88 | list1.printList(); 89 | auto sorted = s.sortList(&list1); 90 | sorted->printList(); 91 | return 0; 92 | } -------------------------------------------------------------------------------- /LinkList/19.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * https://leetcode.cn/problems/remove-nth-node-from-end-of-list/solutions/450350/shan-chu-lian-biao-de-dao-shu-di-nge-jie-dian-b-61/ 3 | * 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 4 | * 三种方法: 5 | * 1. 计数法: 遍历一遍链表得到总长度l,然后第二次遍历到l-n的位置删除节点。时间O(N),空间O(1) 6 | * 2. 栈: 遍历节点时入栈,出栈时统计个数到n,删除节点。时间O(N),空间O(N) 7 | * 3. 双指针:两个指针遍历,第一个指针比第二个指针领先n个节点,这样第一个指针到末尾的时候第二个指针刚好就是带删除元素。时间O(N),空间O(1) 8 | */ 9 | #include "../header.hpp" 10 | /** 11 | * Definition for singly-linked list. 12 | * struct ListNode { 13 | * int val; 14 | * ListNode *next; 15 | * ListNode() : val(0), next(nullptr) {} 16 | * ListNode(int x) : val(x), next(nullptr) {} 17 | * ListNode(int x, ListNode *next) : val(x), next(next) {} 18 | * }; 19 | */ 20 | 21 | 22 | class Solution 23 | { 24 | public: 25 | ListNode *removeNthFromEndStk(ListNode *head, int n) 26 | { 27 | stack stk; 28 | ListNode dummy{0, head}; 29 | ListNode *p = &dummy; 30 | while (p != nullptr) 31 | { 32 | stk.push(p); 33 | p = p->next; 34 | } 35 | for (int i = 0; i < n - 1; i++) 36 | { 37 | stk.pop(); 38 | } 39 | ListNode *tmp = stk.top(); // node to be del 40 | stk.pop(); 41 | ListNode *prev_node = stk.top(); 42 | prev_node->next = tmp->next; 43 | delete tmp; 44 | return dummy.next; 45 | } 46 | 47 | ListNode *removeNthFromEndDoublePtr(ListNode *head, int n) 48 | { 49 | ListNode dummy{0, head}; 50 | ListNode *first = &dummy; 51 | ListNode *second = &dummy; 52 | for (int i = 0; i < n + 1; i++) 53 | { 54 | first = first->next; 55 | } 56 | while (first != nullptr) 57 | { 58 | first = first->next; 59 | second = second->next; 60 | } 61 | // second now points to the prev node of the node to be del 62 | ListNode *to_be_del = second->next; 63 | second->next = second->next->next; 64 | delete to_be_del; 65 | return dummy.next; 66 | } 67 | }; 68 | 69 | int main(int argc, char const *argv[]) 70 | { 71 | vector input = { 72 | 1, 2, 3, 4, 5}; 73 | ListNode *ln = new ListNode{input}; 74 | ln->printList(); 75 | Solution s; 76 | // ln = s.removeNthFromEndStk(ln, 5); 77 | ln = s.removeNthFromEndDoublePtr(ln, 2); 78 | ln->printList(); 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /LinkList/206.cc: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @file 206.reverse_link_list.cpp 4 | * @author SimonKenneth (smkk00715@gmail.com) 5 | * @brief https://leetcode.cn/problems/reverse-linked-list/solutions/ 6 | * @version 0.1 7 | * @date 2024-01-28 8 | * 9 | * @copyright Copyright (c) 2024 10 | * 11 | */ 12 | #include "../header.hpp" 13 | 14 | class Solution 15 | { 16 | public: 17 | ListNode *reverseLinkListStack(ListNode *head) 18 | { 19 | stack tmp_stack; 20 | ListNode *p = head; 21 | while (p != nullptr) 22 | { 23 | tmp_stack.push(p); 24 | p = p->next; 25 | } 26 | ListNode *dummy = new ListNode(0, nullptr); 27 | ListNode *tmp = dummy; 28 | while (!tmp_stack.empty()) 29 | { 30 | ListNode *top = tmp_stack.top(); 31 | tmp_stack.pop(); 32 | /** 33 | * @note the following code will result in recurrent construction 34 | * 35 | * tmp->next = top; 36 | * tmp = top; 37 | */ 38 | top->next = nullptr; // this step is very important 39 | tmp->next = top; 40 | tmp = top; 41 | } 42 | return dummy->next; 43 | } 44 | 45 | /** 46 | * @brief 头插法,即每次将新遍历到的元素插入到链接的头部,实现倒序 47 | * 48 | * @param list 49 | * @return ListNode* 50 | */ 51 | ListNode *reverseLinkListHeadInsert(ListNode *head) 52 | { 53 | ListNode *dummy = new ListNode(); 54 | for (ListNode *curr = head; curr; curr = curr->next) 55 | { 56 | ListNode *p = new ListNode(curr->val, curr->next); 57 | p->next = dummy->next; 58 | dummy->next = p; 59 | } 60 | return dummy->next; 61 | } 62 | }; 63 | 64 | int main(int argc, char const *argv[]) 65 | { 66 | vector input{ 67 | 4, 19, 71, 90, 94}; 68 | ListNode list(input); 69 | list.printList(); 70 | Solution s; 71 | // ListNode *rst = s.reverseLinkListStack(&list); 72 | ListNode *rst = s.reverseLinkListHeadInsert(&list); 73 | rst->printList(); 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /LinkList/23.cc: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "../header.hpp" 4 | 5 | class Solution 6 | { 7 | public: 8 | ListNode *combineList(ListNode *l1, ListNode *l2) 9 | { 10 | ListNode *dummy_node = new ListNode(-1, nullptr); 11 | ListNode *tmp = dummy_node; 12 | 13 | ListNode *p1 = l1, 14 | *p2 = l2; 15 | while (p1 != nullptr && p2 != nullptr) 16 | { 17 | 18 | ListNode *new_node = new ListNode(-1, nullptr); 19 | if (p1->val < p2->val) 20 | { 21 | new_node->val = p1->val; 22 | p1 = p1->next; 23 | } 24 | else 25 | { 26 | new_node->val = p2->val; 27 | p2 = p2->next; 28 | } 29 | tmp->next = new_node; 30 | tmp = new_node; 31 | } 32 | // must exist a list that has not been fullty traversed 33 | if (p1 == nullptr) 34 | { 35 | tmp->next = p2; 36 | } 37 | else 38 | { 39 | tmp->next = p1; 40 | } 41 | return dummy_node->next; // return head pointer 42 | } 43 | }; 44 | 45 | int main(int argc, char const *argv[]) 46 | { 47 | 48 | vector input1{ 49 | 45, 68, 74, 77, 78}; 50 | vector input2{ 51 | 4, 19, 71, 90, 94}; 52 | ListNode l1(input1); 53 | ListNode l2(input2); 54 | // l1.printList(); 55 | // l2.printList(); 56 | Solution s; 57 | ListNode *rst = s.combineList(&l1, &l2); 58 | rst->printList(); 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /LinkList/328.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 3 | * @details 4 | * @url 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | /** 11 | * Definition for singly-linked list. 12 | * struct ListNode { 13 | * int val; 14 | * ListNode *next; 15 | * ListNode() : val(0), next(nullptr) {} 16 | * ListNode(int x) : val(x), next(nullptr) {} 17 | * ListNode(int x, ListNode *next) : val(x), next(next) {} 18 | * }; 19 | */ 20 | class Solution 21 | { 22 | public: 23 | ListNode *oddEvenList(ListNode *head) 24 | { 25 | if (!head || !head->next) return head; 26 | ListNode *odd = head; 27 | ListNode *even = head->next; 28 | ListNode *even_head = even; 29 | while (even && even->next) 30 | { 31 | odd->next = even->next; 32 | odd = odd->next; 33 | even->next = odd->next; 34 | even = even->next; 35 | } 36 | odd->next = even_head; 37 | return head; 38 | } 39 | }; 40 | 41 | int main(int argc, char const *argv[]) 42 | { 43 | Solution s; 44 | return 0; 45 | } -------------------------------------------------------------------------------- /LinkList/92.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 92[M]. 反转链表 II 3 | * @details 4 | * @url https://leetcode.cn/problems/reverse-linked-list-ii/ 5 | * @idea 切断后反转再重连。或者一次取三个节点,不断把下一个节点插到开头。 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | /** 11 | * Definition for singly-linked list. 12 | * struct ListNode { 13 | * int val; 14 | * ListNode *next; 15 | * ListNode() : val(0), next(nullptr) {} 16 | * ListNode(int x) : val(x), next(nullptr) {} 17 | * ListNode(int x, ListNode *next) : val(x), next(next) {} 18 | * }; 19 | */ 20 | class Solution 21 | { 22 | public: 23 | ListNode *reverseBetween(ListNode *head, int left, int right) 24 | { 25 | ListNode *dummy = new ListNode(); // use dummy since left may be 0 26 | dummy->next = head; 27 | ListNode *pre = dummy; 28 | for (int i = 0; i < left - 1; i++) 29 | { 30 | pre = pre->next; 31 | } 32 | ListNode *curr = pre->next; 33 | for (int i = 0; i < right - left; i++) 34 | { 35 | ListNode *next = curr->next; 36 | curr->next = next->next; 37 | next->next = pre->next; 38 | pre->next = next; 39 | } 40 | return dummy->next; 41 | } 42 | }; 43 | 44 | int main(int argc, char const *argv[]) 45 | { 46 | Solution s; 47 | return 0; 48 | } -------------------------------------------------------------------------------- /LinkList/92.reverse_link_list2.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @file 92.reverse_link_list2.cpp 3 | * @author SimonKenneth (smkk00715@gmail.com) 4 | * @brief https://leetcode.cn/problems/reverse-linked-list-ii/description/ 5 | * reverse the nodes from the given left to right in a link list 6 | * @version 0.1 7 | * @date 2024-01-28 8 | * 9 | * @copyright Copyright (c) 2024 10 | * 11 | */ 12 | #include "../header.hpp" 13 | class Solution 14 | { 15 | public: 16 | /** 17 | * @note notice the application of dummy node. it's very important in this problem to enable successful slicing 18 | * 19 | * @param head 20 | * @param left 21 | * @param right 22 | * @return ListNode* 23 | */ 24 | ListNode *reverseLinkListStack(ListNode *head, int left, int right) 25 | { 26 | if (left == right || head->next == nullptr) 27 | { 28 | return head; 29 | } 30 | 31 | stack stk; 32 | ListNode *dummy = new ListNode{-1, head}; 33 | ListNode *p = dummy; 34 | 35 | ListNode *sub_list_prev = dummy; 36 | for (int i = 0; i < left; i++, p = p->next) 37 | { 38 | sub_list_prev = p; 39 | } 40 | // p = p->next; // note p starts from dummy node, so update once more here 41 | ListNode *sub_list_end; 42 | for (int i = 0; i < (right - left) + 1 && p; i++, p = p->next) /** @note don't neglect +1 */ 43 | { 44 | stk.push(p); 45 | } 46 | sub_list_end = p; 47 | 48 | // pop and reverse 49 | ListNode *dummy2 = new ListNode{}; 50 | p = dummy2; 51 | for (; !stk.empty();) 52 | { 53 | ListNode *top = stk.top(); 54 | stk.pop(); 55 | top->next = nullptr; 56 | p->next = top; 57 | p = p->next; 58 | } 59 | p->next = sub_list_end; 60 | sub_list_prev->next = dummy2->next; 61 | return dummy->next; 62 | } 63 | 64 | ListNode *reverseLinkListHeadInsert(ListNode *head, int left, int right) 65 | { 66 | ListNode *dummy = new ListNode(-1, head); 67 | ListNode *p = dummy; 68 | for (int i = 0; i < left - 1; i++, p = p->next) // -1 to stop at the previous node 69 | { 70 | } 71 | ListNode *dummy4sub = p; 72 | ListNode *curr = p->next; 73 | ListNode *sub_first_node; 74 | for (int i = 0; i < (right - left) + 1; i++, curr = curr->next) // note +1 75 | { 76 | ListNode *tmp = new ListNode(curr->val, curr->next); 77 | if (i == 0) 78 | { 79 | tmp->next = nullptr; 80 | sub_first_node = tmp; 81 | } 82 | else 83 | { 84 | tmp->next = dummy4sub->next; 85 | } 86 | dummy4sub->next = tmp; 87 | } 88 | sub_first_node->next = curr; 89 | return dummy->next; 90 | } 91 | }; 92 | 93 | int main(int argc, char const *argv[]) 94 | { 95 | vector input{ 96 | // 1, 2, 3, 4, 5 97 | 3, 5 98 | // 1, 2, 3 99 | }; 100 | ListNode list(input); 101 | list.printList(); 102 | Solution s; 103 | // ListNode *rst = s.reverseLinkListStack(&list, 1, 2); 104 | ListNode *rst = s.reverseLinkListHeadInsert(&list, 1, 2); 105 | rst->printList(); 106 | return 0; 107 | } 108 | -------------------------------------------------------------------------------- /ML/clip.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | from torchvision import models 5 | 6 | class CLIPModel(nn.Module): 7 | def __init__(self, embed_dim, image_model='resnet50', text_vocab_size=10000, text_seq_len=77, text_embed_dim=512): 8 | super(CLIPModel, self).__init__() 9 | 10 | # 图像编码器 11 | self.image_encoder = models.__dict__[image_model](pretrained=True) 12 | self.image_encoder.fc = nn.Linear(self.image_encoder.fc.in_features, embed_dim) 13 | 14 | # 文本编码器 15 | self.text_embedding = nn.Embedding(text_vocab_size, text_embed_dim) 16 | self.text_encoder = nn.Transformer( 17 | d_model=text_embed_dim, 18 | nhead=8, 19 | num_encoder_layers=6, 20 | dim_feedforward=2048 21 | ) 22 | self.text_projection = nn.Linear(text_embed_dim, embed_dim) 23 | 24 | # 温度参数 25 | self.logit_scale = nn.Parameter(torch.ones([]) * torch.log(torch.tensor(1 / 0.07))) 26 | 27 | def forward(self, images, texts): 28 | # 图像编码 29 | image_features = self.image_encoder(images) # [batch_size, embed_dim] 30 | 31 | # 文本编码 32 | text_features = self.text_embedding(texts) # [batch_size, seq_len, text_embed_dim] 33 | text_features = self.text_encoder(text_features.permute(1, 0, 2)) # 交换维度以适配 Transformer 34 | text_features = text_features.mean(dim=0) # 聚合序列信息 35 | text_features = self.text_projection(text_features) # 投射到图像嵌入空间 36 | 37 | # 归一化 38 | image_features = F.normalize(image_features, p=2, dim=-1) 39 | text_features = F.normalize(text_features, p=2, dim=-1) 40 | 41 | # 计算对比学习损失 42 | logit_scale = self.logit_scale.exp() 43 | logits_per_image = logit_scale * image_features @ text_features.t() 44 | logits_per_text = logits_per_image.t() 45 | 46 | return logits_per_image, logits_per_text 47 | 48 | def clip_loss(logits_per_image, logits_per_text): 49 | batch_size = logits_per_image.size(0) 50 | labels = torch.arange(batch_size, device=logits_per_image.device) 51 | 52 | loss_image = F.cross_entropy(logits_per_image, labels) 53 | loss_text = F.cross_entropy(logits_per_text, labels) 54 | 55 | return (loss_image + loss_text) / 2 56 | 57 | # 示例使用 58 | if __name__ == "__main__": 59 | # 示例参数 60 | batch_size = 8 61 | embed_dim = 512 62 | text_vocab_size = 10000 63 | text_seq_len = 77 64 | 65 | # 模拟输入 66 | images = torch.randn(batch_size, 3, 224, 224) 67 | texts = torch.randint(0, text_vocab_size, (batch_size, text_seq_len)) 68 | 69 | # 初始化模型 70 | model = CLIPModel(embed_dim=embed_dim, text_vocab_size=text_vocab_size, text_seq_len=text_seq_len) 71 | 72 | # 前向传播 73 | logits_per_image, logits_per_text = model(images, texts) 74 | 75 | # 计算损失 76 | loss = clip_loss(logits_per_image, logits_per_text) 77 | print(f"CLIP Loss: {loss.item()}") 78 | -------------------------------------------------------------------------------- /ML/conv.py: -------------------------------------------------------------------------------- 1 | def convolve2d(input_matrix, kernel): 2 | input_size = len(input_matrix) 3 | kernel_size = len(kernel) 4 | 5 | output_size = input_size - kernel_size + 1 6 | 7 | output = [[0] * output_size for _ in range(output_size)] 8 | 9 | for i in range(output_size): 10 | for j in range(output_size): 11 | sum = 0 12 | for k in range(kernel_size): 13 | for l in range(kernel_size): 14 | sum += input_matrix[i + k][j + l] * kernel[k][l] 15 | output[i][j] = sum 16 | 17 | return output 18 | 19 | 20 | # 示例:定义输入和卷积核 21 | input_matrix = [[1, 2, 3, 0], [0, 1, 2, 3], [3, 0, 1, 2], [2, 3, 0, 1]] 22 | 23 | kernel = [[2, 0], [0, 1]] 24 | 25 | # 调用函数 26 | result = convolve2d(input_matrix, kernel) 27 | for row in result: 28 | print(row) 29 | -------------------------------------------------------------------------------- /ML/deformable_conv.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | 5 | 6 | class DeformableConv2d(nn.Module): 7 | def __init__(self, in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True): 8 | super(DeformableConv2d, self).__init__() 9 | self.stride = stride 10 | self.padding = padding 11 | self.dilation = dilation 12 | self.kernel_size = kernel_size 13 | 14 | self.offset_conv = nn.Conv2d( 15 | in_channels, 16 | 2 * kernel_size * kernel_size, 17 | kernel_size=kernel_size, 18 | stride=stride, 19 | padding=padding, 20 | dilation=dilation, 21 | groups=groups, 22 | bias=bias, 23 | ) 24 | self.conv = nn.Conv2d( 25 | in_channels, 26 | out_channels, 27 | kernel_size=kernel_size, 28 | stride=stride, 29 | padding=padding, 30 | dilation=dilation, 31 | groups=groups, 32 | bias=bias, 33 | ) 34 | 35 | def forward(self, x): 36 | offset = self.offset_conv(x) 37 | N, _, H, W = offset.shape 38 | p = self._get_p(offset, H, W) 39 | x_offset = self._get_x_offset(x, p) 40 | out = self.conv(x_offset) 41 | return out 42 | 43 | def _get_p(self, offset, H, W): 44 | # Generate the meshgrid for the standard convolutional coordinates 45 | p_h, p_w = torch.meshgrid( 46 | torch.arange(0, self.kernel_size, dtype=torch.float32, device=offset.device), 47 | torch.arange(0, self.kernel_size, dtype=torch.float32, device=offset.device), 48 | ) 49 | p_h = p_h.flatten().repeat(H * W).view(1, 1, -1) 50 | p_w = p_w.flatten().repeat(H * W).view(1, 1, -1) 51 | p_base = torch.cat((p_h, p_w), dim=1).view(1, 2 * self.kernel_size * self.kernel_size, H, W) 52 | return offset + p_base 53 | 54 | def _get_x_offset(self, x, p): 55 | N, C, H, W = x.shape 56 | p = p.permute(0, 2, 3, 1).contiguous() 57 | p = p.view(N, H, W, self.kernel_size * self.kernel_size, 2) 58 | p_h = p[:, :, :, :, 0].unsqueeze(1).repeat(1, C, 1, 1, 1) 59 | p_w = p[:, :, :, :, 1].unsqueeze(1).repeat(1, C, 1, 1, 1) 60 | 61 | # Interpolation 62 | p_h_floor = torch.floor(p_h).long() 63 | p_w_floor = torch.floor(p_w).long() 64 | p_h_ceil = p_h_floor + 1 65 | p_w_ceil = p_w_floor + 1 66 | 67 | # Clipping 68 | p_h_floor = p_h_floor.clamp(0, H - 1) 69 | p_w_floor = p_w_floor.clamp(0, W - 1) 70 | p_h_ceil = p_h_ceil.clamp(0, H - 1) 71 | p_w_ceil = p_w_ceil.clamp(0, W - 1) 72 | 73 | # Gather 4 surrounding points 74 | x_offset = ( 75 | (p_h_ceil.float() - p_h) * (p_w_ceil.float() - p_w) * self._gather_feature(x, p_h_floor, p_w_floor) 76 | + (p_h_ceil.float() - p_h) * (p_w - p_w_floor.float()) * self._gather_feature(x, p_h_floor, p_w_ceil) 77 | + (p_h - p_h_floor.float()) * (p_w_ceil.float() - p_w) * self._gather_feature(x, p_h_ceil, p_w_floor) 78 | + (p_h - p_h_floor.float()) * (p_w - p_w_floor.float()) * self._gather_feature(x, p_h_ceil, p_w_ceil) 79 | ) 80 | 81 | return x_offset 82 | 83 | def _gather_feature(self, x, p_h, p_w): 84 | N, C, H, W = x.shape 85 | p_h = p_h.clamp(0, H - 1) 86 | p_w = p_w.clamp(0, W - 1) 87 | return x[:, :, p_h, p_w].permute(0, 2, 1, 3, 4).contiguous() 88 | 89 | 90 | # 示例用法 91 | x = torch.randn(1, 3, 64, 64) # 输入张量 (N, C, H, W) 92 | deform_conv = DeformableConv2d(3, 64, kernel_size=3, padding=1) 93 | out = deform_conv(x) 94 | print(out.shape) 95 | -------------------------------------------------------------------------------- /ML/focal_loss.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | 5 | 6 | class FocalLoss(nn.Module): 7 | def __init__(self, alpha=1, gamma=2, reduction="mean"): 8 | super(FocalLoss, self).__init__() 9 | self.alpha = alpha 10 | self.gamma = gamma 11 | self.reduction = reduction 12 | 13 | def forward(self, inputs, targets): 14 | # 将输入经过softmax 15 | inputs = F.softmax(inputs, dim=-1) 16 | 17 | # 选择正确类别的概率 18 | pt = inputs.gather(1, targets.unsqueeze(1)).squeeze(1) 19 | 20 | # 计算Focal Loss 21 | loss = -self.alpha * (1 - pt) ** self.gamma * torch.log(pt) 22 | 23 | # 根据 reduction 选项返回损失 24 | if self.reduction == "mean": 25 | return loss.mean() 26 | elif self.reduction == "sum": 27 | return loss.sum() 28 | else: 29 | return loss 30 | 31 | 32 | # 示例使用 33 | if __name__ == "__main__": 34 | # 假设有3个类别 35 | inputs = torch.tensor([[1.5, 0.3, 0.2], [0.1, 2.0, 0.1], [0.05, 0.1, 3.0]]) 36 | targets = torch.tensor([0, 1, 2]) # 真实类别标签 37 | 38 | focal_loss = FocalLoss(alpha=1, gamma=2, reduction="mean") 39 | loss = focal_loss(inputs, targets) 40 | 41 | print(f"Focal Loss: {loss.item()}") 42 | -------------------------------------------------------------------------------- /ML/iou.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def iou(mat1: np.array, mat2: np.array): 5 | """ 6 | mat1: [x1,y1,x2,y2] 7 | """ 8 | x1_inter = max(mat1[0], mat2[0]) 9 | y1_inter = max(mat1[1], mat2[1]) 10 | x2_inter = min(mat1[2], mat2[2]) 11 | y2_inter = min(mat1[3], mat2[3]) 12 | 13 | inter_width = max(0, x2_inter - x1_inter) 14 | inter_height = max(0, y2_inter - y1_inter) 15 | inter_area = inter_width * inter_height 16 | 17 | area_mat1 = (mat1[2] - mat1[0]) * (mat1[3] - mat1[1]) 18 | area_mat2 = (mat2[2] - mat2[0]) * (mat2[3] - mat2[1]) 19 | total_area = area_mat1 + area_mat2 20 | union_area = total_area - inter_area 21 | 22 | iou = inter_area / union_area if union_area != 0 else 0 23 | return iou 24 | -------------------------------------------------------------------------------- /ML/mat_mul.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brian00715/PnC-Interview-Coding/af5170352673544e84492f908664d79f0aed5b25/ML/mat_mul.py -------------------------------------------------------------------------------- /ML/multi_atten.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import numpy as np 4 | 5 | 6 | """手撕多头自注意力""" 7 | 8 | 9 | class MultiHeadAttention(nn.Module): 10 | def __init__(self, input_dim, heads, d_model, dropout=0.1): 11 | super(MultiHeadAttention, self).__init__() 12 | self.d_model = d_model 13 | self.heads = heads 14 | self.input_dim = input_dim 15 | self.d_k = d_model // heads 16 | 17 | self.linear_q = nn.Linear(self.input_dim, self.d_model) 18 | self.linear_k = nn.Linear(self.input_dim, self.d_model) 19 | self.linear_v = nn.Linear(self.input_dim, self.d_model) 20 | 21 | self.dropout = nn.Dropout(dropout) 22 | self.fact = 1 / np.sqrt(self.d_k) 23 | 24 | self.out = nn.Linear(d_model, d_model) 25 | 26 | def forward(self, x, mask=None): 27 | batch_size, seq_len, hidden_size = x.shape 28 | q = self.linear_q(x).view(batch_size, -1, self.heads, self.d_k) 29 | k = self.linear_k(x).view(batch_size, -1, self.heads, self.d_k) 30 | v = self.linear_v(x).view(batch_size, -1, self.heads, self.d_k) 31 | 32 | q = q.transpose(1, 2) 33 | k = k.transpose(1, 2) 34 | v = v.transpose(1, 2) # batch,head,seq_len,d_k 35 | 36 | # 求注意力 37 | score = torch.matmul(q, k.transpose(-2, -1)) * self.fact 38 | if mask is not None: 39 | score = score + mask 40 | 41 | att = torch.softmax(score, dim=-1) 42 | if self.dropout is not None: 43 | att = self.dropout(att) 44 | output = torch.matmul(att, v) # (batch,head,sel_len,d_k) 45 | 46 | # 拼接 47 | concat = output.transpose(1, 2).contiguous().view(batch_size, -1, self.d_model) 48 | 49 | output = self.out(concat) 50 | return output 51 | 52 | 53 | if __name__ == "__main__": 54 | pass 55 | batch = 2 56 | seq_len = 5 57 | input_dim = 32 58 | head = 2 59 | d_model = 32 60 | x = torch.randn(size=(batch, seq_len, input_dim)) 61 | attention = MultiHeadAttention(input_dim, head, d_model) 62 | print(attention(x).shape) 63 | # 求掩码 64 | attention_mask = torch.tril(torch.ones(size=(seq_len, seq_len), dtype=torch.bool)).view(1, 1, seq_len, seq_len) 65 | attention_mask = attention_mask.to(dtype=torch.float16) 66 | attention_mask = (1.0 - attention_mask) * torch.finfo(torch.float16).min 67 | print(attention_mask) 68 | print(attention(x).shape) 69 | -------------------------------------------------------------------------------- /ML/nms.py: -------------------------------------------------------------------------------- 1 | from iou import iou 2 | import numpy as np 3 | import cv2 4 | import sys 5 | 6 | 7 | def nms(boxes: list, scores: list, iou_th: float): 8 | boxes = np.array(boxes) 9 | scores = np.array(scores) 10 | 11 | order = scores.argsort()[::-1] # descent sort 12 | rst = [] # index results 13 | 14 | while order.shape[0] > 0: 15 | i = order[0] # index of box with highest score 16 | rst.append(i) 17 | other_boxes = boxes[order[1:]] 18 | ious = [iou(boxes[i], box) for box in other_boxes] 19 | ious = np.array(ious) 20 | 21 | indexes = np.where(ious <= iou_th)[0] 22 | order = order[1 + indexes] 23 | return rst 24 | 25 | 26 | if __name__ == "__main__": 27 | # img = cv2.imread(sys.path[0] + "/raw_img.png") 28 | boxes = [ 29 | [183, 625, 269, 865], 30 | [197, 603, 296, 853], 31 | [190, 579, 295, 864], 32 | [537, 507, 618, 713], 33 | [535, 523, 606, 687], 34 | ] 35 | # img_box = img.copy() 36 | # for box in boxes: 37 | # top_left = tuple(box[:2]) 38 | # bottom_right = tuple(box[2:]) 39 | # img_box = cv2.rectangle(img, top_left, bottom_right, (0, 0, 0), 2) # 颜色黑色,线宽为2 40 | # cv2.imshow(img_box) 41 | scores = [0.7, 0.9, 0.95, 0.9, 0.6] 42 | iou_threshold = 0.5 43 | 44 | keep_indices = nms(boxes, scores, iou_threshold) 45 | print("保留的边界框索引:", keep_indices) 46 | -------------------------------------------------------------------------------- /ML/self_attention.py: -------------------------------------------------------------------------------- 1 | """ 2 | refer to https://blog.51cto.com/u_14300986/5467376 3 | """ 4 | 5 | import numpy as np 6 | 7 | d = 128 # dimention 8 | n = 32 # number of tokens 9 | Wq = np.random.randn(d, d) 10 | Wk = np.random.randn(d, d) 11 | Wv = np.random.randn(d, d) 12 | 13 | x = np.random.randn(d, n) 14 | 15 | q = Wq @ x 16 | k = Wk @ x 17 | v = Wv @ x 18 | print(f"q_shape:{q.shape}, k_shape:{k.shape}, v_shape:{v.shape}") 19 | 20 | A = q @ k.T 21 | A /= np.sqrt(d) 22 | 23 | 24 | def softmax(A): 25 | ex = np.exp(A - np.max(A)) 26 | return ex / ex.sum(axis=0) 27 | 28 | 29 | A_hat = softmax(A) 30 | output = A_hat @ v 31 | print(f"output_shape:{output.shape}") 32 | 33 | import torch 34 | import torch.nn as nn 35 | 36 | 37 | class SelfAttention(nn.module): 38 | def __init__(self, input_dim, k_dim, v_dim): 39 | super(SelfAttention, self).__init__() 40 | self.Wq = nn.Linear(input_dim, k_dim) 41 | self.Wk = nn.Linear(input_dim, k_dim) 42 | self.Wv = nn.Linear(input_dim, v_dim) 43 | self.norm_factor = np.sqrt(k_dim) 44 | 45 | def forward(self, x): 46 | q = self.Wq(x) 47 | k = self.Wk(x) 48 | v = self.Wv(x) 49 | 50 | atten = ( 51 | nn.Softmax(dim=-1)(torch.bmm(q, k.permute(0, 2, 1))) * self.norm_factor 52 | ) # Q * K.T() # batch_size * seq_len * seq_len 53 | 54 | output = torch.bmm(atten, v) # Q * K.T() * V # batch_size * seq_len * dim_v 55 | -------------------------------------------------------------------------------- /ML/transformer_layer.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | 5 | class MultiHeadSelfAttention(nn.Module): 6 | def __init__(self, embed_dim, num_heads): 7 | super(MultiHeadSelfAttention, self).__init__() 8 | assert embed_dim % num_heads == 0, "Embedding dimension must be divisible by number of heads" 9 | 10 | self.num_heads = num_heads 11 | self.head_dim = embed_dim // num_heads 12 | 13 | self.qkv = nn.Linear(embed_dim, embed_dim * 3) 14 | self.fc_out = nn.Linear(embed_dim, embed_dim) 15 | 16 | def forward(self, x): 17 | batch_size, seq_length, embed_dim = x.size() 18 | 19 | # Compute query, key, and value matrices 20 | qkv = self.qkv(x) # [batch_size, seq_length, 3 * embed_dim] 21 | qkv = qkv.reshape(batch_size, seq_length, 3, self.num_heads, self.head_dim) 22 | qkv = qkv.permute(2, 0, 3, 1, 4) # [3, batch_size, num_heads, seq_length, head_dim] 23 | q, k, v = qkv[0], qkv[1], qkv[2] # Queries, Keys, and Values 24 | 25 | # Scaled Dot-Product Attention 26 | energy = torch.einsum("bhqd, bhkd -> bhqk", q, k) # [batch_size, num_heads, seq_length, seq_length] 27 | scale = torch.sqrt(torch.tensor(self.head_dim, dtype=torch.float32)).to(energy.device) 28 | attention = F.softmax(energy / scale, dim=-1) # Attention weights 29 | 30 | out = torch.einsum("bhqk, bhvd -> bhqd", attention, v) # [batch_size, num_heads, seq_length, head_dim] 31 | out = out.permute(0, 2, 1, 3).reshape(batch_size, seq_length, embed_dim) # Concatenate heads 32 | 33 | # Final linear layer 34 | out = self.fc_out(out) # [batch_size, seq_length, embed_dim] 35 | return out 36 | 37 | class TransformerLayer(nn.Module): 38 | def __init__(self, embed_dim, num_heads, ff_hidden_dim, dropout=0.1): 39 | super(TransformerLayer, self).__init__() 40 | self.self_attention = MultiHeadSelfAttention(embed_dim, num_heads) 41 | self.layernorm1 = nn.LayerNorm(embed_dim) 42 | self.ffn = nn.Sequential( 43 | nn.Linear(embed_dim, ff_hidden_dim), 44 | nn.ReLU(), 45 | nn.Linear(ff_hidden_dim, embed_dim) 46 | ) 47 | self.layernorm2 = nn.LayerNorm(embed_dim) 48 | self.dropout = nn.Dropout(dropout) 49 | 50 | def forward(self, x): 51 | # Self-attention + residual connection + layer normalization 52 | attention_out = self.self_attention(x) 53 | x = self.layernorm1(x + self.dropout(attention_out)) 54 | 55 | # Feedforward network + residual connection + layer normalization 56 | ffn_out = self.ffn(x) 57 | x = self.layernorm2(x + self.dropout(ffn_out)) 58 | 59 | return x 60 | 61 | # 示例使用 62 | if __name__ == "__main__": 63 | batch_size = 32 64 | seq_length = 10 65 | embed_dim = 512 66 | num_heads = 8 67 | ff_hidden_dim = 2048 68 | 69 | # 模拟输入 70 | x = torch.randn(batch_size, seq_length, embed_dim) 71 | 72 | # 初始化 Transformer Layer 73 | transformer_layer = TransformerLayer(embed_dim, num_heads, ff_hidden_dim) 74 | 75 | # 前向传播 76 | out = transformer_layer(x) 77 | print(out.shape) # 输出形状应为 (batch_size, seq_length, embed_dim) 78 | -------------------------------------------------------------------------------- /ML/vit.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torchvision.transforms as transforms 4 | from torchvision.datasets import CIFAR10 5 | from torch.utils.data import DataLoader 6 | 7 | 8 | class PatchEmbedding(nn.Module): 9 | def __init__(self, img_size, patch_size, in_channels, embed_dim): 10 | super().__init__() 11 | self.patch_size = patch_size 12 | self.embed_dim = embed_dim 13 | self.n_patches = (img_size // patch_size) ** 2 14 | self.proj = nn.Conv2d(in_channels, embed_dim, kernel_size=patch_size, stride=patch_size) 15 | 16 | def forward(self, x): 17 | x = self.proj(x) 18 | x = x.flatten(2) 19 | x = x.transpose(1, 2) 20 | return x 21 | 22 | 23 | class MultiHeadSelfAttention(nn.Module): 24 | def __init__(self, embed_dim, num_heads): 25 | super().__init__() 26 | self.embed_dim = embed_dim 27 | self.num_heads = num_heads 28 | self.head_dim = embed_dim // num_heads 29 | 30 | assert self.head_dim * num_heads == embed_dim, "Embedding dimension must be divisible by the number of heads." 31 | 32 | self.qkv = nn.Linear(embed_dim, embed_dim * 3) 33 | self.attention = nn.Softmax(dim=-1) 34 | self.out_proj = nn.Linear(embed_dim, embed_dim) 35 | 36 | def forward(self, x): 37 | batch_size, n_tokens, embed_dim = x.size() 38 | 39 | qkv = self.qkv(x).reshape(batch_size, n_tokens, 3, self.num_heads, self.head_dim) 40 | qkv = qkv.permute(2, 0, 3, 1, 4) 41 | q, k, v = qkv[0], qkv[1], qkv[2] 42 | 43 | attn_weights = (q @ k.transpose(-2, -1)) / (self.head_dim**0.5) 44 | attn_weights = self.attention(attn_weights) 45 | 46 | out = (attn_weights @ v).transpose(1, 2).reshape(batch_size, n_tokens, embed_dim) 47 | out = self.out_proj(out) 48 | return out 49 | 50 | 51 | class MLP(nn.Module): 52 | def __init__(self, embed_dim, mlp_dim): 53 | super().__init__() 54 | self.fc1 = nn.Linear(embed_dim, mlp_dim) 55 | self.fc2 = nn.Linear(mlp_dim, embed_dim) 56 | self.gelu = nn.GELU() 57 | self.dropout = nn.Dropout(0.1) 58 | 59 | def forward(self, x): 60 | x = self.fc1(x) 61 | x = self.gelu(x) 62 | x = self.dropout(x) 63 | x = self.fc2(x) 64 | x = self.dropout(x) 65 | return x 66 | 67 | 68 | class EncoderBlock(nn.Module): 69 | def __init__(self, embed_dim, num_heads, mlp_dim): 70 | super().__init__() 71 | self.norm1 = nn.LayerNorm(embed_dim) 72 | self.norm2 = nn.LayerNorm(embed_dim) 73 | self.msa = MultiHeadSelfAttention(embed_dim, num_heads) 74 | self.mlp = MLP(embed_dim, mlp_dim) 75 | 76 | def forward(self, x): 77 | x = x + self.msa(self.norm1(x)) 78 | x = x + self.mlp(self.norm2(x)) 79 | return x 80 | 81 | 82 | class VisionTransformer(nn.Module): 83 | def __init__( 84 | self, 85 | img_size=32, 86 | patch_size=4, 87 | in_channels=3, 88 | embed_dim=128, 89 | num_heads=4, 90 | mlp_dim=256, 91 | num_layers=6, 92 | num_classes=10, 93 | ): 94 | super().__init__() 95 | self.patch_embedding = PatchEmbedding(img_size, patch_size, in_channels, embed_dim) 96 | self.cls_token = nn.Parameter(torch.randn(1, 1, embed_dim)) 97 | self.pos_embedding = nn.Parameter(torch.randn(1, (img_size // patch_size) ** 2 + 1, embed_dim)) 98 | self.encoder = nn.Sequential(*[EncoderBlock(embed_dim, num_heads, mlp_dim) for _ in range(num_layers)]) 99 | self.mlp_head = nn.Sequential(nn.LayerNorm(embed_dim), nn.Linear(embed_dim, num_classes)) 100 | 101 | def forward(self, x): 102 | batch_size = x.size(0) 103 | x = self.patch_embedding(x) 104 | cls_tokens = self.cls_token.expand(batch_size, -1, -1) 105 | x = torch.cat((cls_tokens, x), dim=1) 106 | x = x + self.pos_embedding 107 | x = self.encoder(x) 108 | cls_logits = self.mlp_head(x[:, 0]) 109 | return cls_logits 110 | 111 | 112 | # 使用CIFAR-10数据集进行训练 113 | transform = transforms.Compose( 114 | [ 115 | transforms.ToTensor(), 116 | transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)), 117 | ] 118 | ) 119 | 120 | trainset = CIFAR10(root="./data", train=True, download=True, transform=transform) 121 | trainloader = DataLoader(trainset, batch_size=64, shuffle=True, num_workers=2) 122 | 123 | testset = CIFAR10(root="./data", train=False, download=True, transform=transform) 124 | testloader = DataLoader(testset, batch_size=64, shuffle=False, num_workers=2) 125 | 126 | device = torch.device("cuda" if torch.cuda.is_available() else "cpu") 127 | model = VisionTransformer().to(device) 128 | criterion = nn.CrossEntropyLoss() 129 | optimizer = torch.optim.Adam(model.parameters(), lr=3e-4) 130 | 131 | # 简单训练循环 132 | for epoch in range(10): 133 | model.train() 134 | for images, labels in trainloader: 135 | images, labels = images.to(device), labels.to(device) 136 | 137 | optimizer.zero_grad() 138 | outputs = model(images) 139 | loss = criterion(outputs, labels) 140 | loss.backward() 141 | optimizer.step() 142 | 143 | print(f"Epoch [{epoch+1}/10], Loss: {loss.item():.4f}") 144 | 145 | # 简单测试 146 | model.eval() 147 | correct = 0 148 | total = 0 149 | with torch.no_grad(): 150 | for images, labels in testloader: 151 | images, labels = images.to(device), labels.to(device) 152 | outputs = model(images) 153 | _, predicted = torch.max(outputs.data, 1) 154 | total += labels.size(0) 155 | correct += (predicted == labels).sum().item() 156 | 157 | print(f"Test Accuracy: {100 * correct / total:.2f}%") 158 | -------------------------------------------------------------------------------- /NumericalComputation/50.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 50.pow(x,y) 3 | * @details 4 | * @url https://leetcode.cn/problems/powx-n/solutions/238559/powx-n-by-leetcode-solution/ 5 | * @idea 递归求解平方,例如x^64 = x^(32)的平方,而不用计算64个x相乘 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | double myPow(double x, int n) 14 | { 15 | long long N = n; 16 | return N > 0 ? subPow(x, N) : 1.0 / subPow(x, N); 17 | } 18 | 19 | double subPow(double x, long long N) 20 | { 21 | if (N == 0) 22 | { 23 | return 1.0; 24 | } 25 | double y = subPow(x, N / 2); 26 | return N % 2 == 0 ? y * y : y * y * x; 27 | } 28 | }; 29 | 30 | int main(int argc, char const *argv[]) 31 | { 32 | Solution s; 33 | } -------------------------------------------------------------------------------- /NumericalComputation/69.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * https://leetcode.cn/problems/sqrtx/ 3 | * 给你一个非负整数 x ,计算并返回 x 的 算术平方根 。 4 | * 由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。 5 | */ 6 | #include "../header.hpp" 7 | class Solution 8 | { 9 | public: 10 | /** 11 | * @brief gradient based method 12 | * 13 | * @param x 14 | * @return int 15 | */ 16 | int mySqrt(int x) 17 | { 18 | if (x == 0) 19 | { 20 | return 0; 21 | } 22 | double c = x, xi = 1; 23 | double lr = 0.001; 24 | for (;;) 25 | { 26 | // obj func: f(x) = (x^2-c)^2 27 | // diff f(x) = 4x(x^2-c) 28 | double gradient = 4 * xi * (xi * xi - c); 29 | double xi_1 = xi - lr * gradient; 30 | double diff = fabs(xi * xi - c); 31 | cout << "xi+1: " << xi_1 << ", diff: " << diff << endl; 32 | if (diff < 1e-6) 33 | { 34 | break; 35 | } 36 | xi = xi_1; 37 | } 38 | return int(xi + 1e-3); 39 | } 40 | 41 | /** 42 | * @brief newton method 43 | * 44 | * @param x 45 | * @return int 46 | */ 47 | int mySqrtNewton(int x) 48 | { 49 | if (x == 0) 50 | { 51 | return 0; 52 | } 53 | double c = x, xi = x; 54 | for (;;) 55 | { 56 | // f(x) = (x^2-c) 57 | // diff f(x) = 2x 58 | double xi_1 = 0.5 * (xi + c / xi); 59 | double diff = xi * xi - c; 60 | cout << "xi+1: " << xi_1 << ", diff: " << diff << endl; 61 | if (diff < 1e-6) 62 | { 63 | break; 64 | } 65 | xi = xi_1; 66 | } 67 | return int(xi); 68 | } 69 | 70 | /** 71 | * @note Numerical overflow will hapen when inputting a large number 72 | */ 73 | int mySqrtBinarySearch(int x) 74 | { 75 | if (x == 0) 76 | { 77 | return 0; 78 | } 79 | double left_interval = 0, right_interval = x; 80 | double xi = x; 81 | double diff = x; 82 | while (fabs(diff) > 1e-6) 83 | { 84 | if (diff > 0) 85 | { 86 | right_interval = xi; 87 | } 88 | else 89 | { 90 | left_interval = xi; 91 | } 92 | xi = (left_interval + right_interval) / 2; 93 | diff = xi * xi - x; 94 | printf("diff: %6.3f, [%6.3f,%6.3f], xi: %6.3f\r\n", diff, left_interval, right_interval, xi); 95 | } 96 | return int(xi + 1e-3); 97 | } 98 | 99 | /** 100 | * there are many boundary problems to be solved in Int-based binary search 101 | */ 102 | int mySqrtBinarySearchInt(int x) 103 | { 104 | if (x == 0) 105 | { 106 | return 0; 107 | } 108 | int left = 0, right = x; 109 | int ans = -1; 110 | while (left <= right) // Must <= 111 | { 112 | int xi = left + (right - left) / 2; 113 | long long diff = (long long)xi * xi - x; 114 | if (diff > 0) // Must >0 115 | { 116 | right = xi - 1; 117 | } 118 | else 119 | { 120 | ans = xi; // assignment must occer at <=0 121 | left = xi + 1; 122 | } 123 | printf("xi: %d [%d,%d]\r\n", xi, left, right); 124 | } 125 | return ans; 126 | } 127 | }; 128 | 129 | int main(int argc, char const *argv[]) 130 | { 131 | Solution sol; 132 | int input; 133 | cout << "input: "; 134 | cin >> input; 135 | cout << "value: " << input << endl; 136 | int result = sol.mySqrtBinarySearchInt(input); 137 | cout << "result: " << result << endl; 138 | return 0; 139 | } 140 | -------------------------------------------------------------------------------- /NumericalComputation/determinant.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brian00715/PnC-Interview-Coding/af5170352673544e84492f908664d79f0aed5b25/NumericalComputation/determinant.cc -------------------------------------------------------------------------------- /NumericalComputation/eigen.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brian00715/PnC-Interview-Coding/af5170352673544e84492f908664d79f0aed5b25/NumericalComputation/eigen.cc -------------------------------------------------------------------------------- /NumericalComputation/eigen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | find_package(Eigen3 REQUIRED PATHS "/Users/simon/Applications/eigen-3.4.0/bin") 2 | 3 | project(eigen_demo) 4 | 5 | add_executable(test test.cc) 6 | target_link_libraries(test Eigen3::Eigen) -------------------------------------------------------------------------------- /NumericalComputation/eigen/test.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using Eigen::MatrixXd; 5 | 6 | int main() 7 | { 8 | MatrixXd m(2, 2); 9 | m(0, 0) = 3; 10 | m(1, 0) = 2.5; 11 | m(0, 1) = -1; 12 | m(1, 1) = m(1, 0) + m(0, 1); 13 | std::cout << m << std::endl; 14 | } 15 | -------------------------------------------------------------------------------- /NumericalComputation/least_square.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * 最小二乘法的实现 3 | */ 4 | #include "../header.hpp" 5 | struct Param 6 | { 7 | double k; 8 | double b; 9 | }; 10 | // cost = sum((yi - k * xi - b)^2) 11 | // \partial{cost}/\partial{b} = 0 12 | // \partial{cost}/\partial{k} = 0 13 | // \partial{ cost } / \partial{ b } = \sum{ 2 * (yi - k * xi - b) } = 0 14 | // ==> b = mean(y) - k * mean(x) 15 | // \partial{ cost } / \partial{ k } = \sum{ 2 * (yi - k * xi - b) * (-xi) } = 0 16 | 17 | Param get_line(vector> points) 18 | { 19 | double y_sum = 0, x_sum = 0; 20 | int num_points = points.size(); 21 | for (int i = 0; i < num_points; ++i) 22 | { 23 | y_sum += points[i][1]; 24 | x_sum += points[i][0]; 25 | } 26 | double y_mean = y_sum / num_points, x_mean = x_sum / num_points; 27 | double sum1 = 0, sum2 = 0; 28 | for (int i = 0; i < num_points; ++i) 29 | { 30 | sum1 += (points[i][1] - y_mean) * points[i][0]; 31 | sum2 += (points[i][0] - x_mean) * points[i][0]; 32 | } 33 | Param res; 34 | res.k = sum1 / (sum2 + 1e-6); 35 | res.b = y_mean - res.k * x_mean; 36 | return res; 37 | } 38 | int main() 39 | { 40 | vector> points = {{0, 1}, {1, 2}, {2, 3}, {3, 4}}; 41 | Param res = get_line(points); 42 | cout << res.k << " " << res.b << endl; 43 | return 0; 44 | } -------------------------------------------------------------------------------- /NumericalComputation/lnx+x^2.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | // 定义目标函数 f(x) = ln(x) + x^2 7 | double f(double x) 8 | { 9 | return log(x) + x * x; 10 | } 11 | 12 | // 定义导数函数 f'(x) = 1/x + 2x 13 | double f_derivative(double x) 14 | { 15 | return 1.0 / x + 2 * x; 16 | } 17 | 18 | // 牛顿法求解 19 | double newton_method(double initial_guess, double tolerance) 20 | { 21 | double x = initial_guess; 22 | double x_next; 23 | 24 | while (true) 25 | { 26 | x_next = x - f(x) / f_derivative(x); 27 | if (fabs(x_next - x) < tolerance) { break; } 28 | x = x_next; 29 | } 30 | 31 | return x_next; 32 | } 33 | 34 | int main() 35 | { 36 | double initial_guess = 0.5; // 初始猜测 37 | double tolerance = 0.0001; // 精度要求 38 | 39 | double solution = newton_method(initial_guess, tolerance); 40 | cout << "方程的近似解为: " << solution << endl; 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /NumericalComputation/matrix_multiply.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 矩阵乘法实现 3 | * @details 4 | * @url 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | #include 10 | 11 | double vectorDotProduct(vector &vec1, vector &vec2) 12 | { 13 | if (vec1.size() != vec2.size()) 14 | { 15 | throw std::runtime_error("dimention error"); 16 | return 0; 17 | } 18 | double sum = 0; 19 | for (int i = 0; i < vec1.size(); i++) { sum += vec1[i] * vec2[i]; } 20 | return sum; 21 | } 22 | 23 | vector> matrixMultiply(vector> &mat1, vector> &mat2) 24 | { 25 | if (mat1.empty() || mat2.empty() || mat1[0].empty() || mat2[0].empty()) 26 | { 27 | throw std::runtime_error("dimention not match!"); 28 | } 29 | int m1 = mat1.size(), n1 = mat1[0].size(); 30 | int m2 = mat2.size(), n2 = mat2[0].size(); 31 | if (n1 != m2) { throw std::runtime_error("dimention not match!"); } 32 | 33 | vector> res(m1, vector(n2)); 34 | for (int i = 0; i < m1; i++) 35 | { 36 | for (int j = 0; j < n2; j++) 37 | { 38 | vector col2; 39 | for (int k = 0; k < m2; k++) { col2.emplace_back(mat2[k][j]); } 40 | res[i][j] = vectorDotProduct(mat1[i], col2); 41 | } 42 | } 43 | return res; 44 | } 45 | 46 | int main() 47 | { 48 | vector> mat1 = {{1, 2, 3}, {4, 5, 6}}; 49 | vector> mat2 = {{7, 8}, {9, 10}, {11, 12}}; 50 | 51 | vector> result = matrixMultiply(mat1, mat2); 52 | 53 | for (const auto &row : result) 54 | { 55 | for (double val : row) { cout << val << " "; } 56 | cout << endl; 57 | } 58 | 59 | return 0; 60 | } -------------------------------------------------------------------------------- /OS/mt_shared_ptr.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brian00715/PnC-Interview-Coding/af5170352673544e84492f908664d79f0aed5b25/OS/mt_shared_ptr.cc -------------------------------------------------------------------------------- /OS/pipe.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @file pipe.cpp 3 | * @author SimonKenneth (smkk00715@gmail.com) 4 | * @brief Introduce the application of pipe communication 5 | * @version 0.1 6 | * @date 2024-01-26 7 | * 8 | * @copyright Copyright (c) 2024 9 | * 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | int main() 21 | { 22 | char message[] = "Hello, named pipe!"; 23 | const char *fifo_path = "/tmp/my_fifo"; // 有名管道的路径 24 | 25 | // 创建有名管道 26 | if (mkfifo(fifo_path, 0666) == -1) 27 | { 28 | perror("mkfifo"); 29 | exit(EXIT_FAILURE); 30 | } 31 | 32 | pid_t child_pid = fork(); 33 | 34 | if (child_pid == -1) 35 | { 36 | perror("fork"); 37 | exit(EXIT_FAILURE); 38 | } 39 | 40 | if (child_pid == 0) 41 | { // 子进程 42 | int fifo_fd = open(fifo_path, O_RDONLY); 43 | if (fifo_fd == -1) 44 | { 45 | perror("open"); 46 | exit(EXIT_FAILURE); 47 | } 48 | 49 | char buffer[1024]; 50 | ssize_t read_bytes = read(fifo_fd, buffer, sizeof(buffer)); 51 | close(fifo_fd); 52 | 53 | if (read_bytes > 0) 54 | { 55 | buffer[read_bytes] = '\0'; 56 | printf("子进程收到消息:'%s'\n", buffer); 57 | } 58 | else 59 | { 60 | printf("无法读取消息。\n"); 61 | } 62 | 63 | exit(EXIT_SUCCESS); 64 | } 65 | else 66 | { 67 | // 父进程 68 | int fifo_fd = open(fifo_path, O_WRONLY); 69 | if (fifo_fd == -1) 70 | { 71 | perror("open"); 72 | exit(EXIT_FAILURE); 73 | } 74 | 75 | ssize_t written_bytes = write(fifo_fd, message, strlen(message)); 76 | close(fifo_fd); 77 | 78 | if (written_bytes == -1) 79 | { 80 | perror("write"); 81 | exit(EXIT_FAILURE); 82 | } 83 | 84 | wait(NULL); // 等待子进程结束 85 | exit(EXIT_SUCCESS); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Others/86.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 86.N皇后问题 3 | * @details 4 | * @url 5 | * @idea 回溯 6 | * @note 暴力解法时间复杂度是C_{N^2}^{N},是一个组合数公式,第一个皇后有N^2个可能的位置,第二个皇后有(N^2-1)个可能的位置,以此类推。 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | vector> solveNQueens(int n) 14 | { 15 | vector> solutions; 16 | vector queens = vector(n, -1); // stores the queens' column index for every row 17 | unordered_set columns; 18 | unordered_set diag1s; 19 | unordered_set diag2s; 20 | 21 | backtrack(solutions, queens, n, 0, columns, diag1s, diag2s); 22 | return solutions; 23 | } 24 | 25 | /** 26 | * @brief 27 | * 28 | * @param solutions final solutions 29 | * @param queens a vector that stores the column indexes for queesn at every row. 30 | * @param n chess board dim 31 | * @param row row index [0,n-1] 32 | * @param columns set that stores column index 33 | * @param diagonals1 set that stores diagonals from up-left to down-right 34 | * @param diagonals2 set that stores diagonals from down-left to up-eight 35 | */ 36 | void backtrack(vector> &solutions, vector &queens, int n, int row, 37 | unordered_set &columns, unordered_set &diagonals1, unordered_set &diagonals2) 38 | { 39 | if (row == n) 40 | { 41 | 42 | vector solution = genBoard(queens, n); 43 | solutions.push_back(solution); 44 | } 45 | else 46 | { 47 | // traverse every column for every row 48 | for (int i = 0; i < n; i++) 49 | { 50 | // check the feasibility for this column 51 | if (columns.find(i) != columns.end()) // occupied 52 | { 53 | continue; 54 | } 55 | int diag1 = row - i; 56 | if (diagonals1.find(diag1) != diagonals1.end()) 57 | { 58 | continue; 59 | } 60 | int diag2 = row + i; 61 | if (diagonals2.find(diag2) != diagonals2.end()) 62 | { 63 | continue; 64 | } 65 | 66 | // every thing is ok, add it! 67 | queens[row] = i; 68 | columns.insert(i); 69 | diagonals1.insert(diag1); 70 | diagonals2.insert(diag2); 71 | backtrack(solutions, queens, n, row + 1, columns, diagonals1, diagonals2); // forward to the next row to get the remaining indexed conditioned by current solution 72 | // cancle the insert operation to garentee the indepency 73 | queens[row] = -1; 74 | columns.erase(i); 75 | diagonals1.erase(diag1); 76 | diagonals2.erase(diag2); 77 | } 78 | } 79 | } 80 | 81 | vector genBoard(vector queens, int dim) 82 | { 83 | vector board; 84 | for (int i = 0; i < dim; i++) 85 | { 86 | string row = string(dim, '.'); 87 | row[queens[i]] = 'Q'; 88 | board.push_back(row); 89 | } 90 | return board; 91 | } 92 | }; 93 | 94 | int main(int argc, char const *argv[]) 95 | { 96 | Solution s; 97 | vector> rst = s.solveNQueens(4); 98 | return 0; 99 | } -------------------------------------------------------------------------------- /Others/bin_search.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name binary search 3 | * @details 4 | * @url 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int binSearch(vector &ar, int target_num) 14 | { 15 | int n = ar.size(); 16 | int left = 0, right = n - 1; 17 | while (left <= right) 18 | { 19 | int mid = (left + right) / 2; 20 | if (ar[mid] > target_num) { right = mid - 1; } 21 | else if (ar[mid] < target_num) { left = mid + 1; } 22 | else { return mid; } 23 | } 24 | return -1; 25 | } 26 | }; 27 | 28 | int main(int argc, char const *argv[]) 29 | { 30 | Solution s; 31 | vector ar = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19}; 32 | int idx = s.binSearch(ar, 5); 33 | cout << idx << endl; 34 | idx = s.binSearch(ar, 11); 35 | cout << idx << endl; 36 | idx = s.binSearch(ar, 19); 37 | cout << idx << endl; 38 | } -------------------------------------------------------------------------------- /Others/class_inherit.cc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brian00715/PnC-Interview-Coding/af5170352673544e84492f908664d79f0aed5b25/Others/class_inherit.cc -------------------------------------------------------------------------------- /Others/shared_ptr.cc: -------------------------------------------------------------------------------- 1 | template class SharedPtr 2 | { 3 | private: 4 | T *ptr; 5 | unsigned *count; 6 | 7 | void release() 8 | { 9 | if (--(*count) == 0) 10 | { 11 | delete ptr; 12 | delete count; 13 | } 14 | } 15 | 16 | public: 17 | // default constructor 18 | SharedPtr() : ptr(nullptr), count(new unsigned(0)) 19 | { 20 | } 21 | 22 | // constructor 23 | explicit SharedPtr(T *obj) : ptr(obj), count(new unsigned(1)) 24 | { 25 | } 26 | 27 | // copy constructor 28 | SharedPtr(const SharedPtr &obj) : ptr(obj.ptr), count(obj.count) 29 | { 30 | ++(*count); 31 | } 32 | 33 | // 移动构造函数 34 | SharedPtr(SharedPtr &&other) noexcept : ptr(other.ptr), count(other.count) 35 | { 36 | other.ptr = nullptr; 37 | other.count = nullptr; 38 | } 39 | 40 | // destructor 41 | ~SharedPtr() 42 | { 43 | release(); 44 | } 45 | 46 | // 拷贝运算符 47 | SharedPtr &operator=(const SharedPtr &other) 48 | { 49 | if (this != &other) 50 | { 51 | release(); 52 | ptr = other.ptr; 53 | count = other.count; 54 | ++(*count); 55 | } 56 | return *this; 57 | } 58 | 59 | // 移动赋值运算符 60 | SharedPtr &operator=(SharedPtr &&other) noexcept 61 | { 62 | if (this != &other) 63 | { 64 | release(); 65 | ptr = other.ptr; 66 | count = other.count; 67 | other.ptr = nullptr; 68 | other.count = nullptr; 69 | } 70 | return *this; 71 | } 72 | 73 | // * operator 74 | T &operator*() const 75 | { 76 | return *ptr; 77 | } 78 | 79 | // -> operator 80 | T *operator->() const 81 | { 82 | return ptr; 83 | } 84 | 85 | // get the current reference count 86 | unsigned get_count() const 87 | { 88 | return *count; 89 | } 90 | 91 | // get the managed pointer 92 | T *get() const 93 | { 94 | return ptr; 95 | } 96 | }; 97 | -------------------------------------------------------------------------------- /Others/singleton.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class Singleton 5 | { 6 | public: 7 | // 禁用拷贝构造函数和赋值操作符 8 | Singleton(const Singleton &) = delete; 9 | Singleton &operator=(const Singleton &) = delete; 10 | 11 | // 获取单例实例的静态方法 12 | static Singleton &getInstance() 13 | { 14 | // 使用局部静态变量,C++11 保证了线程安全 15 | static Singleton instance; 16 | return instance; 17 | } 18 | 19 | void someMethod() { std::cout << "Singleton method called!" << std::endl; } 20 | 21 | private: 22 | // 私有构造函数,防止直接实例化 23 | Singleton() { std::cout << "Singleton constructor called!" << std::endl; } 24 | 25 | // 可选的析构函数(如果需要做一些清理工作) 26 | ~Singleton() { std::cout << "Singleton destructor called!" << std::endl; } 27 | }; 28 | 29 | int main() 30 | { 31 | // 获取单例实例 32 | Singleton &s1 = Singleton::getInstance(); 33 | Singleton &s2 = Singleton::getInstance(); 34 | 35 | // 调用单例的方法 36 | s1.someMethod(); 37 | 38 | // 验证 s1 和 s2 是否为同一个实例 39 | if (&s1 == &s2) { std::cout << "s1 and s2 are the same instance." << std::endl; } 40 | else { std::cout << "s1 and s2 are different instances." << std::endl; } 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /Others/unique_ptr.cc: -------------------------------------------------------------------------------- 1 | template class UniquePtr 2 | { 3 | private: 4 | T *ptr; 5 | 6 | public: 7 | UniquePtr() : ptr(nullptr) 8 | { 9 | } 10 | 11 | explicit UniquePtr(T *obj) : ptr(obj) 12 | { 13 | } 14 | 15 | // 禁用拷贝构造函数 16 | UniquePtr(const UniquePtr &other) = delete; 17 | 18 | // 禁用拷贝赋值运算符 19 | UniquePtr &operator=(const UniquePtr &other) = delete; 20 | 21 | // 移动构造函数 22 | UniquePtr(UniquePtr &&other) noexcept : ptr(other.ptr) 23 | { 24 | other.ptr = nullptr; 25 | } 26 | 27 | // 移动赋值运算符 28 | UniquePtr &operator=(UniquePtr &&other) noexcept 29 | { 30 | if (this != &other) 31 | { 32 | reset(); 33 | ptr = other.ptr; 34 | other.ptr = nullptr; 35 | } 36 | return *this; 37 | } 38 | 39 | ~UniquePtr() 40 | { 41 | reset(); 42 | } 43 | 44 | void reset(T *obj = nullptr) 45 | { 46 | if (ptr) { delete ptr; } 47 | ptr = obj; 48 | } 49 | 50 | T &operator*() const 51 | { 52 | return *ptr; 53 | } 54 | 55 | T *operator->() const 56 | { 57 | return ptr; 58 | } 59 | 60 | T *get() const 61 | { 62 | return ptr; 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /Others/vector.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template class Vector 5 | { 6 | public: 7 | Vector() : _size(0), _capacity(1), _data(new T[1]) 8 | { 9 | } 10 | 11 | ~Vector() 12 | { 13 | delete[] _data; 14 | } 15 | 16 | void push_back(const T &value) 17 | { 18 | if (_size == _capacity) { resize(2 * _capacity); } 19 | _data[_size] = value; 20 | ++_size; 21 | } 22 | 23 | void pop_back() 24 | { 25 | if (_size == 0) { throw std::out_of_range("Vector is empty"); } 26 | --_size; 27 | } 28 | 29 | T &operator[](size_t index) 30 | { 31 | if (index >= _size) { throw std::out_of_range("Index out of bounds"); } 32 | return _data[index]; 33 | } 34 | 35 | const T &operator[](size_t index) const 36 | { 37 | if (index >= _size) { throw std::out_of_range("Index out of bounds"); } 38 | return _data[index]; 39 | } 40 | 41 | size_t size() const 42 | { 43 | return _size; 44 | } 45 | 46 | size_t capacity() const 47 | { 48 | return _capacity; 49 | } 50 | 51 | void resize(size_t new_capacity) 52 | { 53 | T *new_data = new T[new_capacity]; 54 | for (size_t i = 0; i < _size; ++i) 55 | { 56 | new_data[i] = _data[i]; 57 | } 58 | delete[] _data; 59 | _data = new_data; 60 | _capacity = new_capacity; 61 | } 62 | 63 | private: 64 | size_t _size; // 当前元素个数 65 | size_t _capacity; // 容量 66 | T *_data; // 存储数据的指针 67 | }; 68 | 69 | int main() 70 | { 71 | Vector vec; 72 | vec.push_back(10); 73 | vec.push_back(20); 74 | vec.push_back(30); 75 | 76 | std::cout << "Vector elements: "; 77 | for (size_t i = 0; i < vec.size(); ++i) 78 | { 79 | std::cout << vec[i] << " "; 80 | } 81 | std::cout << std::endl; 82 | 83 | std::cout << "Vector size: " << vec.size() << std::endl; 84 | std::cout << "Vector capacity: " << vec.capacity() << std::endl; 85 | 86 | vec.pop_back(); 87 | std::cout << "After pop_back, size: " << vec.size() << std::endl; 88 | 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /SortSearch/quick_sort.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // 分区函数,使用第一个元素作为基准元素,双指针法 5 | int partition(std::vector &arr, int low, int high) 6 | { 7 | int pivot = arr[low]; // 选择第一个元素作为基准 8 | int left = low + 1; // 左指针从第二个元素开始 9 | int right = high; // 右指针从最后一个元素开始 10 | 11 | while (true) 12 | { 13 | while (left <= right && arr[right] > pivot) { right--; } 14 | while (left <= right && arr[left] < pivot) { left++; } 15 | 16 | // 如果左指针超过右指针,结束循环 17 | if (left > right) { break; } 18 | 19 | std::swap(arr[left], arr[right]); 20 | } 21 | 22 | // 交换基准元素与右指针所指的元素 23 | std::swap(arr[low], arr[right]); 24 | 25 | return right; 26 | } 27 | 28 | void quickSort(std::vector &arr, int low, int high) 29 | { 30 | if (low < high) 31 | { 32 | int pi = partition(arr, low, high); // 找到基准元素的位置 33 | 34 | quickSort(arr, low, pi - 1); // 对基准元素左边的部分排序 35 | quickSort(arr, pi + 1, high); // 对基准元素右边的部分排序 36 | } 37 | } 38 | 39 | 40 | // 非递归版本 41 | void quickSortNoRecur(std::vector &arr, int low, int high) {} 42 | 43 | int main() 44 | { 45 | std::vector arr = {10, 7, 8, 9, 1, 5}; 46 | int n = arr.size(); 47 | quickSort(arr, 0, n - 1); 48 | std::cout << "排序后的数组: "; 49 | for (int i = 0; i < n; i++) { std::cout << arr[i] << " "; } 50 | std::cout << std::endl; 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /StackQueue/150.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 150[M]. 逆波兰表达式 3 | * @details 4 | * @url 5 | * https://leetcode.cn/problems/evaluate-reverse-polish-notation/?envType=study-plan-v2&envId=top-interview-150 6 | * @idea 用栈存数字,遇到数字就压入,遇到操作符就连续弹两个数字,算完再压回去,直到遍历完成 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | public: 14 | int evalRPN(vector &tokens) 15 | { 16 | stack st; 17 | int n = tokens.size(); 18 | for (int i = 0; i < n; i++) 19 | { 20 | auto token = tokens[i]; 21 | if (isNum(token)) { st.push(atoi(token.c_str())); } 22 | else 23 | { 24 | int num2 = st.top(); 25 | st.pop(); 26 | int num1 = st.top(); 27 | st.pop(); 28 | switch (token[0]) 29 | { 30 | case '+': 31 | st.push(num1 + num2); 32 | break; 33 | case '-': 34 | st.push(num1 - num2); 35 | break; 36 | case '*': 37 | st.push(num1 * num2); 38 | break; 39 | case '/': 40 | st.push(num1 / num2); 41 | break; 42 | } 43 | } 44 | } 45 | return st.top(); 46 | } 47 | 48 | bool isNum(string token) 49 | { 50 | return !(token == "+" || token == "-" || token == "*" || token == "/"); 51 | } 52 | }; 53 | 54 | int main(int argc, char const *argv[]) 55 | { 56 | Solution s; 57 | return 0; 58 | } -------------------------------------------------------------------------------- /StackQueue/20.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 20.有效的括号 3 | * @details 4 | 5 | 给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。 6 | 7 | 有效字符串需满足: 8 | 9 | 左括号必须用相同类型的右括号闭合。 10 | 左括号必须以正确的顺序闭合。 11 | 每个右括号都有一个对应的相同类型的左括号。 12 | 输入:s = "()[]{}" 13 | 输出:true 14 | 15 | * @url https://leetcode.cn/problems/valid-parentheses/description/ 16 | * @idea 用栈和字典实现括号匹配 17 | * @note 18 | */ 19 | #include "../header.hpp" 20 | 21 | class Solution 22 | { 23 | public: 24 | bool isValid(string s) 25 | { 26 | stack bracket; 27 | for (char ch : s) 28 | { 29 | if (bracket.empty() && ch == '}' || 30 | bracket.empty() && ch == ')' || 31 | bracket.empty() && ch == ']') // does not have the matched left bracket 32 | { 33 | return false; 34 | } 35 | 36 | if (ch == '(' || ch == '{' || ch == '[') 37 | { 38 | bracket.push(ch); 39 | } 40 | else 41 | { 42 | if ((ch == ')' && bracket.top() == '(') || 43 | (ch == '}' && bracket.top() == '{') || 44 | (ch == ']' && bracket.top() == '[')) // match 45 | { 46 | bracket.pop(); 47 | } 48 | else 49 | { 50 | return false; 51 | } 52 | } 53 | } 54 | if (bracket.empty()) 55 | return true; 56 | else 57 | return false; 58 | } 59 | }; 60 | 61 | int main(int argc, char const *argv[]) 62 | { 63 | Solution s; 64 | string input{"()[]{}"}; 65 | bool rst = s.isValid(input); 66 | printf("the input is %s\r\n", rst ? "true" : "false"); 67 | } -------------------------------------------------------------------------------- /StackQueue/239.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 239.滑动窗口最大值 3 | * @details 4 | * @url https://leetcode.cn/problems/sliding-window-maximum/description/ 5 | * @idea 6 | * 优先队列维护滑动窗口内的最大值,不断取堆顶元素。注意要不断弹出堆顶元素以确保堆中都是滑动窗口内的元素 7 | * @note 8 | */ 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | public: 14 | vector maxSlidingWindow(vector &nums, int k) 15 | { 16 | int size = nums.size(); 17 | priority_queue> heap; // value,index 18 | 19 | for (int i = 0; i < k; i++) { heap.emplace(nums[i], i); } 20 | 21 | vector ans; 22 | ans.push_back(heap.top().first); 23 | for (int i = k; i < size; i++) 24 | { 25 | heap.emplace(nums[i], i); 26 | while (heap.top().second <= i - k) // ensure the numbers in head exist in window 27 | { 28 | heap.pop(); 29 | } 30 | int top_num = heap.top().first; 31 | ans.push_back(top_num); 32 | } 33 | return ans; 34 | } 35 | }; 36 | 37 | int main(int argc, char const *argv[]) { Solution s; } -------------------------------------------------------------------------------- /StackQueue/prefix_expression.py: -------------------------------------------------------------------------------- 1 | def evaluate_prefix(expression): 2 | stack = [] 3 | operators = set(["+", "-", "*", "/"]) 4 | 5 | # 从右向左扫描表达式 6 | for token in reversed(expression.split()): 7 | if token in operators: 8 | # 弹出栈顶的两个操作数 9 | operand1 = stack.pop() 10 | operand2 = stack.pop() 11 | 12 | # 计算并将结果压入栈中 13 | if token == "+": 14 | result = operand1 + operand2 15 | elif token == "-": 16 | result = operand1 - operand2 17 | elif token == "*": 18 | result = operand1 * operand2 19 | elif token == "/": 20 | result = operand1 / operand2 21 | 22 | stack.append(result) 23 | else: 24 | # 将操作数压入栈中 25 | stack.append(int(token)) 26 | 27 | # 栈顶元素即为最终结果 28 | return stack.pop() 29 | 30 | 31 | # 测试 32 | expression = "- + * 2 3 * 5 4 9" 33 | result = evaluate_prefix(expression) 34 | print("前缀表达式的值为:", result) 35 | -------------------------------------------------------------------------------- /String/5.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 5.最长回文子串 3 | * @details 4 | * @url 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int functionName() 14 | { 15 | return 0; 16 | } 17 | }; 18 | 19 | int main(int argc, char const *argv[]) 20 | { 21 | Solution s; 22 | } -------------------------------------------------------------------------------- /Tree/102.cc: -------------------------------------------------------------------------------- 1 | /* 2 | 二叉树层序遍历 3 | https://leetcode.cn/problems/binary-tree-level-order-traversal/description/ 4 | */ 5 | #include "../header.hpp" 6 | 7 | class Solution 8 | { 9 | public: 10 | vector> layerTraverse(TreeNode *root) 11 | { 12 | vector> rst; 13 | if (root == nullptr) 14 | { 15 | return rst; 16 | } 17 | queue open_list; 18 | open_list.push(root); 19 | 20 | while (!open_list.empty()) 21 | { 22 | int n = open_list.size(); // for distinguishing every layer's result 23 | vector layer_rst; 24 | for (int i = 0; i < n; i++) 25 | { 26 | TreeNode *curr = open_list.front(); 27 | open_list.pop(); 28 | layer_rst.push_back(curr->val); 29 | 30 | if (curr->left != nullptr) 31 | { 32 | open_list.push(curr->left); 33 | } 34 | if (curr->right != nullptr) 35 | { 36 | 37 | open_list.push(curr->right); 38 | } 39 | } 40 | rst.push_back(layer_rst); 41 | } 42 | return rst; 43 | } 44 | }; 45 | 46 | int main(int argc, char const *argv[]) 47 | { 48 | Solution s; 49 | vector input{ 50 | 3, 9, 20, -1, -1, 15, 7}; 51 | 52 | TreeNode tree(input); 53 | tree.traverse(TreeNode::TraverseMethod::LEVEL); 54 | vector> rst; 55 | rst = s.layerTraverse(&tree); 56 | for (auto layer : rst) 57 | { 58 | for (auto x : layer) 59 | { 60 | cout << x << " "; 61 | } 62 | cout << endl; 63 | } 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /Tree/104.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 104.求二叉树最大深度 3 | * @details 4 | * @url https://leetcode.cn/problems/maximum-depth-of-binary-tree/description/ 5 | * @idea 递归,取左、右子树最大深度的最大值+1 6 | * @note 7 | */ 8 | 9 | #include "../header.hpp" 10 | 11 | class Solution 12 | { 13 | public: 14 | int maxDepth(TreeNode *root) 15 | { 16 | if (root == nullptr) 17 | { 18 | return 0; 19 | } 20 | return max(maxDepth(root->left), maxDepth(root->right)) + 1; 21 | } 22 | 23 | int maxDepthBFS(TreeNode *root) 24 | { 25 | queue q; 26 | if (root != nullptr) 27 | q.push(root); 28 | int ans = 0; 29 | while (!q.empty()) 30 | { 31 | int n = q.size(); // XXX important 32 | for (int i = 0; i < n; i++) 33 | { 34 | TreeNode *curr = q.front(); 35 | q.pop(); 36 | if (curr->left != nullptr) 37 | { 38 | q.push(curr->left); 39 | }; 40 | if (curr->right != nullptr) 41 | { 42 | q.push(curr->right); 43 | }; 44 | } 45 | ans++; 46 | } 47 | return ans; 48 | } 49 | }; 50 | 51 | int main(int argc, char const *argv[]) 52 | { 53 | 54 | Solution s; 55 | vector input{ 56 | 3, 9, 20, -1, -1, 15, 7}; 57 | 58 | TreeNode tree(input); 59 | tree.traverse(TreeNode::TraverseMethod::LEVEL); 60 | 61 | // int rst = s.maxDepth(&tree); 62 | int rst = s.maxDepthBFS(&tree); 63 | cout << "max depth: " << rst << endl; 64 | return 0; 65 | } -------------------------------------------------------------------------------- /Tree/105.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 3 | * @details 4 | * @url 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | int post_idx; 13 | unordered_map idx_map; 14 | 15 | public: 16 | TreeNode *helper(int in_left, int in_right, vector &inorder, vector &postorder) 17 | { 18 | // 如果这里没有节点构造二叉树了,就结束 19 | if (in_left > in_right) { return nullptr; } 20 | 21 | // 选择 post_idx 位置的元素作为当前子树根节点 22 | int root_val = postorder[post_idx]; 23 | TreeNode *root = new TreeNode(root_val); 24 | 25 | // 根据 root 所在位置分成左右两棵子树 26 | int index = idx_map[root_val]; 27 | 28 | // 下标减一 29 | post_idx--; 30 | // 构造右子树 31 | root->right = helper(index + 1, in_right, inorder, postorder); 32 | // 构造左子树 33 | root->left = helper(in_left, index - 1, inorder, postorder); 34 | return root; 35 | } 36 | TreeNode *buildTree(vector &inorder, vector &postorder) 37 | { 38 | // 从后序遍历的最后一个元素开始 39 | post_idx = (int)postorder.size() - 1; 40 | 41 | // 建立(元素,下标)键值对的哈希表 42 | int idx = 0; 43 | for (auto &val : inorder) 44 | { 45 | idx_map[val] = idx++; 46 | } 47 | return helper(0, (int)inorder.size() - 1, inorder, postorder); 48 | } 49 | }; 50 | 51 | int main(int argc, char const *argv[]) 52 | { 53 | Solution s; 54 | return 0; 55 | } -------------------------------------------------------------------------------- /Tree/226.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 3 | * @details 4 | * @url 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | TreeNode *invertTree(TreeNode *root) 14 | { 15 | if (root == nullptr) 16 | { 17 | return nullptr; 18 | } 19 | TreeNode *left = invertTree(root->left); 20 | TreeNode *right = invertTree(root->right); 21 | root->left = right; 22 | root->right = left; 23 | return root; 24 | } 25 | }; 26 | int main(int argc, char const *argv[]) 27 | { 28 | Solution s; 29 | } -------------------------------------------------------------------------------- /Tree/236.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 236.二叉树的最近公共祖先 3 | * @details 4 | * @url https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/description/ 5 | * @idea dfs,注意最近公共祖先的判读即可 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | /** 11 | * Definition for a binary tree node. 12 | * struct TreeNode { 13 | * int val; 14 | * TreeNode *left; 15 | * TreeNode *right; 16 | * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 17 | * }; 18 | */ 19 | class Solution 20 | { 21 | public: 22 | TreeNode *ans; 23 | TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q) 24 | { 25 | dfs(root, p, q); 26 | return ans; 27 | } 28 | 29 | bool dfs(TreeNode *root, TreeNode *p, TreeNode *q) 30 | { 31 | if (!root) return false; 32 | bool lchild = dfs(root->left, p, q); 33 | bool rchild = dfs(root->right, p, q); 34 | if ((lchild && rchild) || 35 | ((root->val == p->val || root->val == q->val) && (lchild || rchild))) 36 | { 37 | ans = root; 38 | } 39 | return lchild || rchild || (root->val == p->val || root->val == q->val); 40 | } 41 | }; 42 | 43 | int main(int argc, char const *argv[]) 44 | { 45 | Solution s; 46 | return 0; 47 | } -------------------------------------------------------------------------------- /Tree/654.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 654[M]. 最大二叉树 3 | * @details 4 | * @url https://leetcode.cn/problems/maximum-binary-tree/description/ 5 | * @idea 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | class Solution 11 | { 12 | public: 13 | int functionName() 14 | { 15 | return 0; 16 | } 17 | }; 18 | 19 | int main(int argc, char const *argv[]) 20 | { 21 | Solution s; 22 | return 0; 23 | } -------------------------------------------------------------------------------- /Tree/98.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 98. 验证二叉搜索树 3 | * @details 4 | * @url https://leetcode.cn/problems/validate-binary-search-tree/description/ 5 | * @idea DFS判断是否满足要求或者用中序遍历看是否是递增序列 6 | * @note DFS时注意传递给递归函数的参数 7 | */ 8 | #include "../header.hpp" 9 | 10 | /** 11 | * Definition for a binary tree node. 12 | * struct TreeNode { 13 | * int val; 14 | * TreeNode *left; 15 | * TreeNode *right; 16 | * TreeNode() : val(0), left(nullptr), right(nullptr) {} 17 | * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 18 | * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} 19 | * }; 20 | */ 21 | class Solution 22 | { 23 | private: 24 | bool judge(TreeNode *root, long long left, long long right) 25 | { 26 | if (root == nullptr) 27 | { 28 | return true; 29 | } 30 | if (root->val <= left || root->val >= right) // must be >= or <= !!! 31 | { 32 | return false; 33 | } 34 | return judge(root->left, left, root->val) && judge(root->right, root->val, right); 35 | } 36 | 37 | public: 38 | bool isValidBST(TreeNode *root) 39 | { 40 | return judge(root, LONG_MIN, LONG_MAX); 41 | } 42 | }; 43 | 44 | int main(int argc, char const *argv[]) 45 | { 46 | Solution s; 47 | } -------------------------------------------------------------------------------- /Tree/cow_group.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * @name 牛群仰视图 3 | * @details 4 | * @url https://www.nowcoder.com/practice/0f37a18320c4466abf3a65819592e8be?tab=note 5 | * @idea 实际就是遍历叶子结点,DFS就完事了.注意叶子结点的定义是左child和右child都为空 6 | * @note 7 | */ 8 | #include "../header.hpp" 9 | 10 | /** 11 | * struct TreeNode { 12 | * int val; 13 | * struct TreeNode *left; 14 | * struct TreeNode *right; 15 | * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 16 | * }; 17 | */ 18 | class Solution 19 | { 20 | public: 21 | /** 22 | * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 23 | * 24 | * 25 | * @param root TreeNode类 26 | * @return int整型vector 27 | */ 28 | vector bottomView(TreeNode *root) 29 | { 30 | vector res; 31 | traverse(root, res); 32 | return res; 33 | } 34 | 35 | void traverse(TreeNode *root, vector &res) 36 | { 37 | if (!root) return; 38 | if (!root->left && !root->right) res.push_back(root->val); 39 | 40 | traverse(root->left, res); 41 | traverse(root->right, res); 42 | } 43 | }; 44 | 45 | int main(int argc, char const *argv[]) 46 | { 47 | Solution s; 48 | return 0; 49 | } -------------------------------------------------------------------------------- /Tree/stand_traverse.cc: -------------------------------------------------------------------------------- 1 | #include "../header.hpp" 2 | 3 | class Solution 4 | { 5 | 6 | vector &traverseTree(TreeNode *root) 7 | { 8 | vector result; 9 | preTraverse(root, result); 10 | return result; 11 | } 12 | 13 | void preTraverse(TreeNode *root, vector &rst) 14 | { 15 | // mid left right 16 | if (root == nullptr) 17 | { 18 | return; 19 | } 20 | rst.push_back(root->val); 21 | preTraverse(root->left, rst); 22 | preTraverse(root->right, rst); 23 | } 24 | 25 | void midTraverse(TreeNode *root, vector &rst) 26 | { 27 | if (root == nullptr) 28 | { 29 | return; 30 | } 31 | // left mid right 32 | midTraverse(root->left, rst); 33 | rst.push_back(root->val); 34 | midTraverse(root->right, rst); 35 | } 36 | 37 | void postTraverse(TreeNode *root, vector &rst) 38 | { 39 | if (root == nullptr) 40 | { 41 | return; 42 | } 43 | // left right mid 44 | postTraverse(root->left, rst); 45 | postTraverse(root->right, rst); 46 | rst.push_back(root->val); 47 | } 48 | 49 | void layerTraverse(TreeNode *root, vector &rst) 50 | { 51 | queue tmp; 52 | tmp.push(root); 53 | while (!tmp.empty()) 54 | { 55 | TreeNode *node = tmp.front(); 56 | tmp.pop(); 57 | if (node->left) 58 | { 59 | tmp.push(node->left); 60 | } 61 | if (node->right) 62 | { 63 | tmp.push(node->right); 64 | } 65 | } 66 | } 67 | }; 68 | class Solution 69 | { 70 | 71 | vector &traverseTree(TreeNode *root) 72 | { 73 | vector result; 74 | preTraverse(root, result); 75 | return result; 76 | } 77 | 78 | void preTraverse(TreeNode *root, vector &rst) 79 | { 80 | // mid left right 81 | if (root == nullptr) 82 | { 83 | return; 84 | } 85 | rst.push_back(root->val); 86 | preTraverse(root->left, rst); 87 | preTraverse(root->right, rst); 88 | } 89 | 90 | void midTraverse(TreeNode *root, vector &rst) 91 | { 92 | if (root == nullptr) 93 | { 94 | return; 95 | } 96 | // left mid right 97 | midTraverse(root->left, rst); 98 | rst.push_back(root->val); 99 | midTraverse(root->right, rst); 100 | } 101 | 102 | void postTraverse(TreeNode *root, vector &rst) 103 | { 104 | if (root == nullptr) 105 | { 106 | return; 107 | } 108 | // left right mid 109 | postTraverse(root->left, rst); 110 | postTraverse(root->right, rst); 111 | rst.push_back(root->val); 112 | } 113 | 114 | void layerTraverse(TreeNode *root, vector &rst) 115 | { 116 | queue tmp; 117 | tmp.push(root); 118 | while (!tmp.empty()) 119 | { 120 | TreeNode *node = tmp.front(); 121 | tmp.pop(); 122 | if (node->left) 123 | { 124 | tmp.push(node->left); 125 | } 126 | if (node->right) 127 | { 128 | tmp.push(node->right); 129 | } 130 | } 131 | } 132 | }; 133 | 134 | int main() 135 | { 136 | // 创建一个最小堆的优先队列(默认情况下) 137 | // std::priority_queue, std::greater> min_heap; 138 | std::priority_queue> min_heap; 139 | 140 | // 插入元素 141 | min_heap.push(3); 142 | min_heap.push(1); 143 | min_heap.push(4); 144 | min_heap.push(2); 145 | 146 | // 访问队首元素(最小元素) 147 | std::cout << "Top element: " << min_heap.top() << std::endl; 148 | 149 | // 弹出队首元素 150 | min_heap.pop(); 151 | 152 | // 输出剩余元素 153 | while (!min_heap.empty()) 154 | { 155 | std::cout << min_heap.top() << " "; 156 | min_heap.pop(); 157 | } 158 | std::cout << std::endl; 159 | 160 | return 0; 161 | } 162 | -------------------------------------------------------------------------------- /clean.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | """Recursively clean all files and folders without the enxtension .cpp or .hpp""" 3 | 4 | import os 5 | import shutil 6 | 7 | must_clean_keywords = [ 8 | "sync-conflict", 9 | ] 10 | ignore_exts = [ 11 | "cpp", 12 | "cc", 13 | "hpp", 14 | "py", 15 | "c", 16 | "h", 17 | "txt", 18 | "md", 19 | "json", 20 | "sh", 21 | "code-snippets", 22 | "gitignore", 23 | "clang-format", 24 | ".git", 25 | ] 26 | igore_dirs = [".vscode", ".git", "./.git"] 27 | dir_keywords = [".dSYM", "build", "test", "__pycache__"] 28 | 29 | 30 | def clean(path, debug=False): 31 | """Recursively clean all files and folders without the enxtension .cpp or .hpp""" 32 | for root, dirs, files in os.walk(path): 33 | dirs[:] = [d for d in dirs if d not in ignore_exts] 34 | 35 | for file in files: 36 | if file.split(".")[-1] not in ignore_exts or sum([1 if x in file else 0 for x in must_clean_keywords]) >= 1: 37 | os.remove(os.path.join(root, file)) 38 | print(f"remove {os.path.join(root, file)}") 39 | pass 40 | for dir in dirs: 41 | if dir in igore_dirs: 42 | continue 43 | if any(keyword in dir for keyword in dir_keywords): 44 | shutil.rmtree(os.path.join(root, dir)) 45 | print(f"remove dir {os.path.join(root, dir)}") 46 | 47 | 48 | if __name__ == "__main__": 49 | clean(".", debug=True) 50 | -------------------------------------------------------------------------------- /count.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Directory to be searched 4 | DIRECTORY="." 5 | 6 | # Extensions of code files to be searched (add more as needed) 7 | EXTENSIONS=("py" "cpp" "c" "hpp" "cc" "h") 8 | 9 | # Initialize file and line count 10 | FILE_COUNT=0 11 | LINE_COUNT=0 12 | 13 | # Function to count lines in a file 14 | count_lines() { 15 | local file="$1" 16 | local lines=$(wc -l < "$file") 17 | echo "$lines" 18 | } 19 | 20 | # Main loop to go through files 21 | for ext in "${EXTENSIONS[@]}"; do 22 | while IFS= read -r -d '' file; do 23 | FILE_COUNT=$((FILE_COUNT + 1)) 24 | LINE_COUNT=$((LINE_COUNT + $(count_lines "$file"))) 25 | done < <(find "$DIRECTORY" -name "*.$ext" -print0) 26 | done 27 | 28 | # Output results 29 | echo "Number of code files: $FILE_COUNT" 30 | echo "Total lines of code: $LINE_COUNT" 31 | -------------------------------------------------------------------------------- /header.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace std; 12 | 13 | void PrintMatrix(const vector> &matrix) 14 | { 15 | cout << "matrix(" << matrix.size() << "," << matrix[0].size() << ") ------------------" << endl; 16 | for (const auto &row : matrix) 17 | { 18 | for (const auto &elem : row) 19 | { 20 | cout << elem << " "; 21 | } 22 | cout << endl; 23 | } 24 | cout << "----------------------------------" << endl; 25 | } 26 | 27 | void PrintVector(const vector &vector) 28 | { 29 | cout << "vector(" << vector.size() << ") ------------------" << endl; 30 | for (const auto &elem : vector) 31 | { 32 | 33 | cout << elem << " "; 34 | } 35 | cout << endl << "----------------------------------" << endl; 36 | } 37 | 38 | struct ListNode 39 | { 40 | int val; 41 | ListNode *next; 42 | ListNode() : val(0), next(nullptr) 43 | { 44 | } 45 | ListNode(int x) : val(x), next(nullptr) 46 | { 47 | } 48 | ListNode(int x, ListNode *next) : val(x), next(next) 49 | { 50 | } 51 | ListNode(ListNode &node) : val(node.val), next(node.next) 52 | { 53 | } 54 | ListNode(ListNode *node) : val(node->val), next(node->next) 55 | { 56 | } 57 | 58 | ListNode(vector &data) 59 | { 60 | int flag = 1; 61 | ListNode *rear = nullptr; 62 | for (auto element : data) 63 | { 64 | if (flag == 1) 65 | { 66 | this->val = element; 67 | flag++; 68 | rear = this; 69 | } 70 | else 71 | { 72 | ListNode *new_node = new ListNode{element}; 73 | rear->next = new_node; 74 | rear = new_node; 75 | } 76 | } 77 | } 78 | 79 | void printList() 80 | { 81 | ListNode *p = this; 82 | while (p != nullptr) 83 | { 84 | cout << p->val << " "; 85 | p = p->next; 86 | } 87 | cout << endl; 88 | } 89 | }; 90 | 91 | class Graph 92 | { 93 | public: 94 | Graph(int size) : size(size) 95 | { 96 | adj = vector>(size, vector(size, 0)); 97 | } 98 | 99 | Graph(vector> input) : adj(input), size(input.size()) 100 | { 101 | } 102 | 103 | void addEdge(int u, int v, float w) 104 | { 105 | adj[u][v] = w; 106 | } 107 | 108 | /** 109 | * @brief traverse from start to end. only output traverse path, not the path from start to end 110 | * 111 | */ 112 | virtual void bfs(int start, int end) 113 | { 114 | bool *visited = new bool[size]; 115 | for (int i = 0; i < size; i++) 116 | { 117 | visited[i] = false; 118 | } 119 | 120 | std::queue q; 121 | q.push(start); 122 | visited[start] = true; 123 | 124 | cout << "BFS result: "; 125 | while (!q.empty()) 126 | { 127 | int u = q.front(); 128 | q.pop(); 129 | cout << u + 1 << " "; 130 | if (u == end) 131 | { 132 | std::cout << "Found" << std::endl; 133 | break; 134 | } 135 | // traverse all the adjacent nodes 136 | for (int i = 0; i < size; i++) 137 | { 138 | if (adj[u][i] != 0 && !visited[i]) 139 | { 140 | visited[i] = true; 141 | q.push(i); 142 | } 143 | } 144 | } 145 | cout << endl; 146 | } 147 | 148 | virtual void dfs(int start, int end) 149 | { 150 | vector visited(size, false); 151 | 152 | std::stack s; 153 | s.push(start); 154 | visited[start] = true; 155 | cout << "DFS result: "; 156 | while (!s.empty()) 157 | { 158 | int u = s.top(); 159 | s.pop(); 160 | cout << u + 1 << " "; 161 | if (u == end) 162 | { 163 | std::cout << "Found" << std::endl; 164 | break; 165 | } 166 | // traverse all the adjacent nodes 167 | for (int i = 0; i < size; i++) 168 | { 169 | if (adj[u][i] != 0 && !visited[i]) 170 | { 171 | visited[i] = true; 172 | s.push(i); 173 | } 174 | } 175 | } 176 | cout << endl; 177 | } 178 | 179 | void printAdj() 180 | { 181 | for (int i = 0; i < size; i++) 182 | { 183 | std::cout << i << ": "; 184 | for (int j = 0; j < size; j++) 185 | { 186 | std::cout << adj[i][j] << " "; 187 | } 188 | std::cout << std::endl; 189 | } 190 | } 191 | 192 | float calcu_sum_weights(std::vector path) 193 | { 194 | float sum = 0; 195 | for (int i = 0; i < path.size() - 1; i++) 196 | { 197 | sum += adj[path[i]][path[i + 1]]; 198 | } 199 | return sum; 200 | } 201 | 202 | private: 203 | vector> adj; 204 | int size; 205 | }; 206 | 207 | class TreeNode 208 | { 209 | public: 210 | int val; 211 | TreeNode *left; 212 | TreeNode *right; 213 | TreeNode(int x) : val(x), left(nullptr), right(nullptr) 214 | { 215 | } 216 | 217 | const vector TraverseMethodString{"pre-order", "mid-order", "post-order", 218 | "level-order"}; 219 | 220 | enum class TraverseMethod 221 | { 222 | PRE = 0, 223 | MID, 224 | POST, 225 | LEVEL 226 | }; 227 | 228 | /** 229 | * @brief Construct a new Tree Node object given the level-order-traverse result in the form of 230 | * 1-D vector 231 | * 232 | * @param levelOrder 233 | */ 234 | TreeNode(vector &levelOrder) 235 | { 236 | if (levelOrder.empty()) 237 | { 238 | val = -1; 239 | left = nullptr; 240 | right = nullptr; 241 | } 242 | 243 | val = levelOrder[0]; 244 | queue q; 245 | q.push(this); 246 | 247 | int index = 1; // build from the second element 248 | 249 | while (index < levelOrder.size()) 250 | { 251 | TreeNode *current = q.front(); 252 | q.pop(); 253 | 254 | // build left tree 255 | if (index < levelOrder.size() && levelOrder[index] != -1) 256 | { 257 | current->left = new TreeNode(levelOrder[index]); 258 | q.push(current->left); 259 | } 260 | index++; 261 | 262 | // build right tree 263 | if (index < levelOrder.size() && levelOrder[index] != -1) 264 | { 265 | current->right = new TreeNode(levelOrder[index]); 266 | q.push(current->right); 267 | } 268 | index++; 269 | } 270 | } 271 | 272 | void traverse(TreeNode::TraverseMethod opt = TreeNode::TraverseMethod::PRE) 273 | { 274 | printf("%s result: ", TraverseMethodString[(int)opt].c_str()); 275 | switch (opt) 276 | { 277 | case TraverseMethod::PRE: 278 | prevTraverse(this); 279 | break; 280 | case TraverseMethod::MID: 281 | midTraverse(this); 282 | break; 283 | case TraverseMethod::POST: 284 | postTraverse(this); 285 | break; 286 | case TraverseMethod::LEVEL: 287 | layerTraverse(this); 288 | break; 289 | default: 290 | break; 291 | } 292 | cout << endl; 293 | } 294 | 295 | private: 296 | void prevTraverse(TreeNode *root) 297 | { 298 | if (root == nullptr) 299 | { 300 | cout << "null "; 301 | return; 302 | } 303 | 304 | cout << root->val << " "; 305 | prevTraverse(root->left); 306 | prevTraverse(root->right); 307 | } 308 | void midTraverse(TreeNode *root) 309 | { 310 | if (root == nullptr) 311 | { 312 | cout << "null "; 313 | return; 314 | } 315 | 316 | midTraverse(root->left); 317 | cout << root->val << " "; 318 | midTraverse(root->right); 319 | } 320 | 321 | void postTraverse(TreeNode *root) 322 | { 323 | if (root == nullptr) 324 | { 325 | cout << "null "; 326 | return; 327 | } 328 | 329 | postTraverse(root->left); 330 | postTraverse(root->right); 331 | cout << root->val << " "; 332 | } 333 | 334 | void layerTraverse(TreeNode *root) 335 | { 336 | queue q; 337 | q.push(root); 338 | while (!q.empty()) 339 | { 340 | TreeNode *curr = q.front(); 341 | q.pop(); 342 | if (curr == nullptr) { cout << "null "; } 343 | else 344 | { 345 | cout << curr->val << " "; 346 | q.push(curr->left); 347 | q.push(curr->right); 348 | } 349 | } 350 | cout << endl; 351 | } 352 | }; 353 | -------------------------------------------------------------------------------- /main.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | /** 7 | * @brief Get the max steal object 8 | * 9 | * @param rooms 10 | * @return int max stealing value 11 | */ 12 | int get_max_steal(vector rooms) 13 | { 14 | int n = rooms.size(); 15 | vector dp(n + 1, 0); 16 | dp[0] = rooms[0]; 17 | dp[1] = max(rooms[0], rooms[1]); 18 | 19 | for (int i = 2; i < n; i++) 20 | { 21 | dp[i] = max(dp[i - 1], dp[i - 2] + rooms[i]); 22 | } 23 | return dp[n - 1]; 24 | } 25 | 26 | int main() 27 | { 28 | vector rooms={2,7,9,3,1}; 29 | int max_value = get_max_steal(rooms); 30 | cout< 1: 16 | dp[x][y][p] += dp[x - 1][y][p - 1] 17 | if x < m: 18 | dp[x][y][p] += dp[x + 1][y][p - 1] 19 | if y > 1: 20 | dp[x][y][p] += dp[x][y - 1][p - 1] 21 | if y < n: 22 | dp[x][y][p] += dp[x][y + 1][p - 1] 23 | 24 | # 最终结果为到达 (m, n) 恰好经过 P 个站点的路径数 25 | return dp[m][n][P] 26 | 27 | # 处理输入 28 | m, n, P = map(int, input().split()) 29 | matrix = [list(map(int, input().split())) for _ in range(m)] 30 | 31 | # 计算并输出结果 32 | result = count_paths(m, n, P) 33 | print(result) 34 | --------------------------------------------------------------------------------