数组
1 2 3
| vector<int> ret; ret.back(); ret[ret.size() - 1];
|
堆
1 2
| priority_queue<pair<int, int>, vector<pair<int, int>>, less<pair<int, int>>> pri_que;
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| struct compare { bool operator()(ListNode* a, ListNode* b) { return a -> val > b -> val; } };
class Solution { public: ListNode* mergeKLists(vector<ListNode*>& lists) { priority_queue<ListNode*, vector<ListNode*>, compare> pq; } }
|
循环
善用auto&和冒号循环
1 2 3 4
| vector<int> temp; for(auto& t : temp) {
}
|
二分法技巧
1
| middle = left + (right - left) / 2
|
(left + right) / 2 可能会整形溢出。
取值范围
在取值范围比较大的情况下,为了防止溢出,可以采用 int64_t 类型。
[int8_t]
sizeof(int8_t) = 1 byte(s) = 8 bit(s)
MIN = -128
MAX = 127
[int16_t]
sizeof(int16_t) = 2 byte(s) = 16 bit(s)
MIN = -32768
MAX = 32767
[int32_t]
sizeof(int32_t) = 4 byte(s) = 32 bit(s)
MIN = -2147483648
MAX = 2147483647
[int64_t]
sizeof(int64_t) = 8 byte(s) = 64 bit(s)
MIN = -9223372036854775808
MAX = 9223372036854775807
检测结果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
| ╔══════════════════════════════════════════════════════════════════════╗ ║ 整数类型取值范围检测(C++ integer type ranges) ║ ╚══════════════════════════════════════════════════════════════════════╝
【一】平台基本整数类型(大小因平台/编译器而异) ------------------------------------------------------------------------ [short] sizeof(short) = 2 byte(s) = 16 bit(s) MIN = -32768 MAX = 32767
[int] sizeof(int) = 4 byte(s) = 32 bit(s) MIN = -2147483648 MAX = 2147483647
[long] sizeof(long) = 4 byte(s) = 32 bit(s) MIN = -2147483648 MAX = 2147483647
[long long] sizeof(long long) = 8 byte(s) = 64 bit(s) MIN = -9223372036854775808 MAX = 9223372036854775807
[unsigned short] sizeof(unsigned short) = 2 byte(s) = 16 bit(s) MIN = 0 MAX = 65535
[unsigned int] sizeof(unsigned int) = 4 byte(s) = 32 bit(s) MIN = 0 MAX = 4294967295
[unsigned long] sizeof(unsigned long) = 4 byte(s) = 32 bit(s) MIN = 0 MAX = 4294967295
[unsigned long long] sizeof(unsigned long long) = 8 byte(s) = 64 bit(s) MIN = 0 MAX = 18446744073709551615
【二】<climits> 极值宏(对应基本类型) ------------------------------------------------------------------------ -- short -- SHRT_MIN = -32768 SHRT_MAX = 32767 USHRT_MAX = 65535
-- int -- INT_MIN = -2147483648 INT_MAX = 2147483647 UINT_MAX = 4294967295
-- long -- LONG_MIN = -2147483648 LONG_MAX = 2147483647 ULONG_MAX = 4294967295
-- long long -- LLONG_MIN = -9223372036854775808 LLONG_MAX = 9223372036854775807 ULLONG_MAX = 18446744073709551615
【三】<cstdint> 固定宽度整数类型(大小严格固定,跨平台首选) ------------------------------------------------------------------------ [int8_t] sizeof(int8_t) = 1 byte(s) = 8 bit(s) MIN = -128 MAX = 127
[int16_t] sizeof(int16_t) = 2 byte(s) = 16 bit(s) MIN = -32768 MAX = 32767
[int32_t] sizeof(int32_t) = 4 byte(s) = 32 bit(s) MIN = -2147483648 MAX = 2147483647
[int64_t] sizeof(int64_t) = 8 byte(s) = 64 bit(s) MIN = -9223372036854775808 MAX = 9223372036854775807
[uint8_t] sizeof(uint8_t) = 1 byte(s) = 8 bit(s) MIN = 0 MAX = 255
[uint16_t] sizeof(uint16_t) = 2 byte(s) = 16 bit(s) MIN = 0 MAX = 65535
[uint32_t] sizeof(uint32_t) = 4 byte(s) = 32 bit(s) MIN = 0 MAX = 4294967295
[uint64_t] sizeof(uint64_t) = 8 byte(s) = 64 bit(s) MIN = 0 MAX = 18446744073709551615
【四】<cstdint> 固定宽度类型的极值宏 ------------------------------------------------------------------------ -- int8_t / uint8_t -- INT8_MIN = -128 INT8_MAX = 127 UINT8_MAX = 255
-- int16_t / uint16_t -- INT16_MIN = -32768 INT16_MAX = 32767 UINT16_MAX = 65535
-- int32_t / uint32_t -- INT32_MIN = -2147483648 INT32_MAX = 2147483647 UINT32_MAX = 4294967295
-- int64_t / uint64_t -- INT64_MIN = -9223372036854775808 INT64_MAX = 9223372036854775807 UINT64_MAX = 18446744073709551615
【五】最大/最小宽度类型(intmax_t / intptr_t / size_t / ptrdiff_t) ------------------------------------------------------------------------ [intmax_t] sizeof(intmax_t) = 8 byte(s) = 64 bit(s) MIN = -9223372036854775808 MAX = 9223372036854775807
[uintmax_t] sizeof(uintmax_t) = 8 byte(s) = 64 bit(s) MIN = 0 MAX = 18446744073709551615
[intptr_t] sizeof(intptr_t) = 8 byte(s) = 64 bit(s) MIN = -9223372036854775808 MAX = 9223372036854775807
[uintptr_t] sizeof(uintptr_t) = 8 byte(s) = 64 bit(s) MIN = 0 MAX = 18446744073709551615
[size_t] sizeof(size_t) = 8 byte(s) = 64 bit(s) MIN = 0 MAX = 18446744073709551615
[ptrdiff_t] sizeof(ptrdiff_t) = 8 byte(s) = 64 bit(s) MIN = -9223372036854775808 MAX = 9223372036854775807
【六】平台指针宽度(判断 32 位 / 64 位) ------------------------------------------------------------------------ sizeof(void*) = 8 byte(s) ➜ 当前为 64 位平台
════════════════════════════════════════════════════════════════════════ 检测完毕!
|
检测脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
| #include <iostream> #include <climits> #include <cstdint> #include <limits> #include <cstddef> #include <iomanip>
#define SEP() std::cout << std::string(72, '-') << "\n"
#define PRINT_SIZE(T) \ std::cout << " sizeof(" #T ") = " << sizeof(T) << " byte(s) = " \ << sizeof(T)*8 << " bit(s)\n"
#define PRINT_SIGNED(T) \ std::cout << " [" #T "]\n"; \ PRINT_SIZE(T); \ std::cout << " MIN = " << (long long)std::numeric_limits<T>::min() << "\n"; \ std::cout << " MAX = " << (long long)std::numeric_limits<T>::max() << "\n\n"
#define PRINT_UNSIGNED(T) \ std::cout << " [" #T "]\n"; \ PRINT_SIZE(T); \ std::cout << " MIN = 0\n"; \ std::cout << " MAX = " << (unsigned long long)std::numeric_limits<T>::max() << "\n\n"
#define PRINT_MACRO(name) \ std::cout << " " #name " = " << (long long)(name) << "\n" #define PRINT_UMACRO(name) \ std::cout << " " #name " = " << (unsigned long long)(name) << "\n"
int main() { std::cout << std::left;
std::cout << "╔══════════════════════════════════════════════════════════════════════╗\n"; std::cout << "║ 整数类型取值范围检测(C++ integer type ranges) ║\n"; std::cout << "╚══════════════════════════════════════════════════════════════════════╝\n\n";
std::cout << "【一】平台基本整数类型(大小因平台/编译器而异)\n"; SEP();
PRINT_SIGNED(short); PRINT_SIGNED(int); PRINT_SIGNED(long); PRINT_SIGNED(long long);
PRINT_UNSIGNED(unsigned short); PRINT_UNSIGNED(unsigned int); PRINT_UNSIGNED(unsigned long); PRINT_UNSIGNED(unsigned long long);
std::cout << "【二】<climits> 极值宏(对应基本类型)\n"; SEP();
std::cout << " -- short --\n"; PRINT_MACRO(SHRT_MIN); PRINT_MACRO(SHRT_MAX); PRINT_UMACRO(USHRT_MAX);
std::cout << "\n -- int --\n"; PRINT_MACRO(INT_MIN); PRINT_MACRO(INT_MAX); PRINT_UMACRO(UINT_MAX);
std::cout << "\n -- long --\n"; PRINT_MACRO(LONG_MIN); PRINT_MACRO(LONG_MAX); PRINT_UMACRO(ULONG_MAX);
std::cout << "\n -- long long --\n"; PRINT_MACRO(LLONG_MIN); PRINT_MACRO(LLONG_MAX); PRINT_UMACRO(ULLONG_MAX); std::cout << "\n";
std::cout << "【三】<cstdint> 固定宽度整数类型(大小严格固定,跨平台首选)\n"; SEP();
PRINT_SIGNED(int8_t); PRINT_SIGNED(int16_t); PRINT_SIGNED(int32_t); PRINT_SIGNED(int64_t);
PRINT_UNSIGNED(uint8_t); PRINT_UNSIGNED(uint16_t); PRINT_UNSIGNED(uint32_t); PRINT_UNSIGNED(uint64_t);
std::cout << "【四】<cstdint> 固定宽度类型的极值宏\n"; SEP();
std::cout << " -- int8_t / uint8_t --\n"; PRINT_MACRO(INT8_MIN); PRINT_MACRO(INT8_MAX); PRINT_UMACRO(UINT8_MAX); std::cout << "\n -- int16_t / uint16_t --\n"; PRINT_MACRO(INT16_MIN); PRINT_MACRO(INT16_MAX); PRINT_UMACRO(UINT16_MAX); std::cout << "\n -- int32_t / uint32_t --\n"; PRINT_MACRO(INT32_MIN); PRINT_MACRO(INT32_MAX); PRINT_UMACRO(UINT32_MAX); std::cout << "\n -- int64_t / uint64_t --\n"; PRINT_MACRO(INT64_MIN); PRINT_MACRO(INT64_MAX); PRINT_UMACRO(UINT64_MAX); std::cout << "\n";
std::cout << "【五】最大/最小宽度类型(intmax_t / intptr_t / size_t / ptrdiff_t)\n"; SEP();
PRINT_SIGNED(intmax_t); PRINT_UNSIGNED(uintmax_t); PRINT_SIGNED(intptr_t); PRINT_UNSIGNED(uintptr_t); PRINT_UNSIGNED(size_t); PRINT_SIGNED(ptrdiff_t);
std::cout << "【六】平台指针宽度(判断 32 位 / 64 位)\n"; SEP();
std::cout << " sizeof(void*) = " << sizeof(void*) << " byte(s)\n"; if (sizeof(void*) == 8) std::cout << " ➜ 当前为 64 位平台\n\n"; else if (sizeof(void*) == 4) std::cout << " ➜ 当前为 32 位平台\n\n"; else std::cout << " ➜ 未知平台\n\n";
std::cout << "════════════════════════════════════════════════════════════════════════\n"; std::cout << "检测完毕!\n";
return 0; }
|
善用tie和pair
1 2
| stack<pair<TreeNode*, int>> st; auto [node, depth] = st.top();
|
函数返回pair,可以用tie
1 2 3 4 5 6 7
| pair<ListNode*, ListNode*> myReverse(head, tail);
tie(head, tail) = myReverse(head, tail);
|
双重遍历优化思路
对比两个数组中相同的元素,可以将一个数组存入 unordered_set(哈希表)中,然后再遍历另一个数组去哈希表中查找。这样可以将寻找交点的时间复杂度从 O(N2) 降到 O(N)。
树形动态规划
在树的动态规划问题中,通常只要是从底向上(后序遍历)收集信息,我们都可以尝试在递归归的过程中直接消化掉这些信息,从而省去额外的存储结构。
两种搜索方法
广度优先搜索(BFS):就像一块石头丢进水里,水波纹一层一层向外扩散。通常借助**队列(Queue)来实现。
深度优先搜索(DFS):就像走迷宫,认准一个方向一条路走到黑,碰壁了再退回来走另一条路。通常借助递归(Recursion)或栈(Stack)**来实现。
数组初始化
一些数组初始化赋值方法。
1 2 3 4 5 6 7 8 9 10
| class A { public: vector<vector<int>> graph; vector<int> visited; void buildGraph(int num) { graph.resize(num); visited.assign(numCourses, 0); }
|
三色标记法
对于一些标记数组,可以不使用 true/false 的这种 bool 数组,而是使用 int 数组表示多种状态,如 0 表示未访问、1 表示访问中、2 表示已访问。
vector和list元素操作
vector:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| vector<int> vec = {10, 20, 30, 40, 50};
int first = vec.front(); int last = vec.back(); int second = vec[1];
vec.pop_back();
vec.erase(vec.begin() + 2);
vec.erase(vec.begin() + 1, vec.begin() + 3);
|
list:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| list<int> lst = {10, 20, 20, 30, 40, 50};
int first = lst.front(); int last = lst.back();
lst.push_front(10);
lst.push_back(10);
lst.pop_front();
lst.pop_back();
lst.remove(20);
vector<int> vec(lst.begin(), lst.end()); vector<int> vec = vector<int>(lst.begin(), lst.end());
|
获取字符串子串
使用成员函数 substr()。该函数接受两个参数:起始位置(pos)和长度(len),并返回一个从指定位置开始、指定长度的子串。若不指定长度,则默认提取到字符串结尾。
1 2 3 4 5
| string s1 = "Hello, World!";
string s2 = s1.substr(7, 5);
string s3 = s1.substr(7);
|
枚举思路——以N皇后为例
我们很容易看出需要使用枚举的方法来求解这个问题,当我们不知道用什么办法来枚举是最优的时候,可以从下面三个方向考虑:
- 子集枚举:可以把问题转化成「从 n2 个格子中选一个子集,使得子集中恰好有 n 个格子,且任意选出两个都不在同行、同列或者同对角线」,这里枚举的规模是 2n2;
- 组合枚举:可以把问题转化成「从 n2 个格子中选择 n 个,且任意选出两个都不在同行、同列或者同对角线」,这里的枚举规模是 (nn2);
- 排列枚举:因为这里每行只能放置一个皇后,而所有行中皇后的列号正好构成一个 1 到 n 的排列,所以我们可以把问题转化为一个排列枚举,规模是 n!。
带入一些 n 进这三种方法验证,就可以知道哪种方法的枚举规模是最小的,这里我们发现第三种方法的枚举规模最小。这道题给出的两个方法其实和排列枚举的本质是类似的。
二分法
可以手写/调库。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| int left = 0, right = end_col; while (left <= right) { int mid = left + (right - left) / 2; if (matrix[i][mid] == target) { return true; } else if (matrix[i][mid] < target) { left = mid + 1; } else { right = mid - 1; } }
vector<int> v = {10, 20, 30, 30, 30, 40, 50}; int target = 30;
auto lo = lower_bound(v.begin(), v.end(), target, less<int>()); auto hi = upper_bound(v.begin(), v.end(), target, less<int>());
comp(target, *it)
bool exists = std::binary_search(v.begin(), v.end(), target, less<int>());
int lo_idx = lo - v.begin(); int hi_idx = hi - v.begin();
if (lo != v.end() && *lo == target) { } else { }
|