底层是用红黑树实现的,查找的平均复杂度是log(n),map的key是有序的,因为是用红黑树实现的,所以key是中序遍历出来的。
hash_map是用hash实现的map,key是无序的,hash_map查询是O(1)的。
hashtable就是手写的hash表。
用virtual关键字申明的函数叫做虚函数,是类的成员函数,虚函数是用于实现多态的机制,核心理念就是通过基类访问派生类定义的函数,只能借助于指针或者引用来达到多态的效果。
存在虚函数的类都有一个一维的虚函数表叫做虚表。当类中声明虚函数时,编译器会在类中生成一个虚函数表,其中存放着该类所有的虚函数对应的函数指针。
构造函数不能为虚函数,而析构函数常常是虚函数。
C++结构体的继承默认是public,而c++类的继承默认是private。
C++结构体内部成员变量及成员函数默认的访问级别是public,而c++类的内部成员变量及成员函数的默认访问级别是private。
多态分为静态多态与动态多态。
#define N 2+3
我们预想的N值是5,我们 int a = N/2
,我们预想的a的值是2,可实际上a的值是3。原因在于在预处理阶段,编译器将 a = N/2处理成了 a = 2+3/2
。int const* p
和 const int* p
是常量指针,也就是说这个指针指向的值不能变,但是这个指针的地址可以变。
int *const p
是指针常量,指针的地址不能变,但是指向的值可以变,所以要初始化。
程序申请的内存空间,在使用完毕后未释放,一直占据内存单元。
解决方法:良好的代码习惯,在涉及内存的程序段检测内存泄漏。重载new和delete,主要思路是将分配的内存以链表的形式自行管理,使用完成之后从链表中删除,程序结束时可检查该链表,当中记录了内存泄露的文件,所在文件的行数以及泄露的大小。
作用是监控内存的使用以及释放内存。首先指针只能是由两个类构成,分为引用计数类和指针类,其实智能指针的本质是类,但是看起来像指针。动态分配的资源,交给一个类对象去管理,当类对象声明周期结束时,自动调用析构函数释放资源,防止内存泄漏。
优点
缺点
管道、消息队列、共享内存、套接字、信号量
大体可分为两类:用户模式和内核模式
申请方式和回收方式不同
申请后系统的响应
申请效率的比较
申请大小的限制
堆和栈中的存储内容
存取效率的比较
可以。
Linux中每个文件都会有2个link计数器——i_count 和 i_nlink
,删除操作只是将 i_nlink
置为 0 了,由于文件被进程引用的缘故,i_count
不为 0,所以系统没有真正删除这个文件。i_nlink
是文件删除的充分条件,而 i_count
才是文件删除的必要条件。
TCP可靠传输的关键部分。
防止已失效的连接请求报文段突然又传送到了B,因而产生错误。
如A发出连接请求,但因连接请求报文丢失而未收到确认,于是A再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接。但是第一个丢失的报文段只是在某些网络结点长时间滞留了,延误到连接释放后才到达B,此时B误认为A又发出一次新的连接请求,于是就向A发出确认报文段,同意建立连接。不采用三次握手,只要B发出确认,就建立新的连接了,此时A不理睬B的确认且不发送数据,则B一致等待A发送数据,浪费资源。
当服务器端收到客户端的连接请求报文后,可以把SYN和ACK报文一起发送。其中ACK报文是用来应答的,SYN报文是用来同步的。但关闭连接时,当收到对方的FIN报文通知时,它仅仅表示对方没有数据发送给你了,但服务器端未必所有的数据都全部发送给对方了,可能还需要发送一些数据给对方之后,再发送FIN报文给对方来表示现在可以关闭连接了。
滑动窗口:窗口大小指的是无需等待确认应答而可以继续发送数据的最大值,窗口越大, 则网络的吞吐率就越高。
接收窗口只有在前面所有的段都确认的情况下才会移动左边界,收到了一个返回确认的ACK之后窗口就往后移动继续发送在窗口里的数据。
跳表是redis的一个核心组件,也被广泛地运用到了各种缓存地实现当中。它的主要优点就是可以跟红黑树、平衡树一样,做到比较稳定地插入、查询与删除。时间复杂度为O(logN),代码相对简单。
一种二叉查找树,每个节点有标记颜色
数据库索引是为了增加查询速度而对表字段附加的一种标识。
应该建索引的字段:
应该少建或者不建索引的字段:
保持两个数据库的状态自动同步。对任何一个数据库的操作都自动应用到另外一个数据库,始终保持两个数据库数据一致。
优点:
ListNode* reverseList(ListNode* head) {
ListNode *cur = head;
ListNode *tmp, *prev = NULL;
while (cur) {
tmp = cur->next;
cur->next = prev;
prev = cur;
cur = tmp;
}
return prev;
}
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
ListNode* deleteDuplicates(ListNode* head) {
ListNode *left = head, *right;
while(left) {
right = left->next;
if(right && left->val == right->val) {
left->next = right->next;
delete right;
}
else left = right;
}
return head;
}
递归实现:
void MirrorRecursively(TreeNode *pRoot)
{
if(pRoot == NULL) return;
TreeNode *pTemp = pRoot->left;
pRoot->left = pRoot->right;
pRoot->right = pTemp;
if(pRoot->left) MirrorRecursively(pRoot->left);
if(pRoot->right) MirrorRecursively(pRoot->right);
}
非递归实现:
void MirrorIteratively(TreeNode* pRoot)
{
if(pRoot == NULL) return;
stack<TreeNode*> stk;
stk.push(pRoot);
while(!stk.empty()) {
TreeNode *pNode = stk.top(); stackTreeNode.pop();
TreeNode *pTemp = pNode->left;
pNode->left = pNode->right;
pNode->right = pTemp;
if(pNode->left) stackTreeNode.push(pNode->left);
if(pNode->right) stackTreeNode.push(pNode->right);
}
}
int maxV(BTNode *root){
if(root == null) return INF;
if(maxV(root.left) > maxV(root.right)) swap(root.left, root.right);
return max(root.v, maxV(root.left), maxV(root.left));
}
void preOrder2(BinTree *root) { // 非递归实现前序遍历
stack<BinTree*> s;
BinTree *p = root;
while(p != NULL || !s.empty()) {
while(p != NULL) {
cout << p->data << " ";
s.push(p);
p = p->lchild;
}
if(!s.empty()) {
p = s.top(); s.pop();
p = p->rchild;
}
}
}
void inOrder2(BinTree *root) { // 非递归中序遍历
stack<BinTree*> s;
BinTree *p = root;
while(p != NULL || !s.empty()) {
while(p != NULL) {
s.push(p);
p = p->lchild;
}
if(!s.empty()) {
p = s.top(); s.pop();
cout << p->data <<" ";
p=p->rchild;
}
}
}
vector<int> postOrder(TreeNode *root) {
vector<int> res;
if(root == NULL) return res;
TreeNode *p = root;
stack<TreeNode *> sta;
TreeNode *last = root;
sta.push(p);
while (!sta.empty()) {
p = sta.top();
if((p->left == NULL && p->right == NULL)
|| (p->right == NULL && last == p->left)
|| (last == p->right)) {
res.push_back(p->val);
last = p;
sta.pop();
}
else {
if(p->right) sta.push(p->right);
if(p->left) sta.push(p->left);
}
}
return res;
}
参考博客:https://blog.csdn.net/u010025211/article/details/49668017
int Rand7(){
while(x > 21) // x > 7 会导致[8, 25]的数都被浪费掉
x = 5 * (rand(5) - 1) + rand(5) // x = rand(25)
return x%7 + 1;
}
用 rand(a) 和 rand(b) 生成 rand(a * b):
rand(a*b) = a * (rand(b) - 1) + rand(a)
有一栋楼共100层,一个鸡蛋从第N层及以上的楼层落下来会摔破, 在第N层以下的楼层落下不会摔破。给你2个鸡蛋,设计方案找出N,并且保证在最坏情况下, 最小化鸡蛋下落的次数。(假设每次摔落时,如果没有摔碎,则不会给鸡蛋带来损耗)
for(int i = 1; i <= d; i++) dp[1][i] = i;
for(int i = 1; i <= e; i++) dp[i][1] = 1;
for(int i = 2; i <= e; i++)
{
for(int j = 2; j <= d; j++)
{
int MIN = 1 + max(dp[i - 1][0], dp[i][j - 1] + 1);
for(int k = 1; k <= j; k++)
{
MIN = min(MIN, 1 + max(dp[i - 1][k - 1], dp[i][j - k]));
}
dp[i][j] = MIN;
}
}
printf("%d\n", dp[e][d]);
提示:先考虑2行m列有多少种摆法,再算n行m列
对于每列来说情况相同,对于搭一列的问题,就是走楼梯问题,一次可以走一步或者两步,总共有多少种走法。
dp[i][0] += dp[i-1][0..3]
dp[i][1] += dp[i-1][0, 2]
dp[i][2] += dp[i-1][0, 1]
dp[i][3] += dp[i-1][0]
int get_kth_smallest(vector<int>& nums1, int st1, const int& sz1, vector<int>& nums2, int st2, const int& sz2, int k) {
// 保证nums1.size() <= nums2.size(),方便分析
if (sz1-st1 > sz2-st2) return get_kth_smallest(nums2, st2, sz2, nums1, st1, sz1, k);
if (sz1 - st1 == 0) return nums2[k-1 + st2];
if (1 == k) return nums1[st1] < nums2[st2]? nums1[st1]:nums2[st2];
// 在nums1和nums2中分别取第k/2个数字。如果超出边界,取最后那个数字
int k1 = min(sz1-st1, k/2);
int k2 = min(sz2-st2, k/2);
// 如果nums1[k1-1] < nums2[k2-1],说明nums1[k1-1]小于要找的第k小
if (nums1[st1+k1-1] < nums2[st2+k2-1]) return get_kth_smallest(nums1, st1+k1, sz1, nums2, st2, sz2, k-k1);
// 如果nums1[k1-1] > nums2[k2-1],说明nums2[k2-1]小于要找的第k小
// 如果nums1[k1-1] == nums2[k2-1],说明nums2[k2-1]小于等于要找的第k小。但是依然可以删掉它,因为还有nums1[k1-1]和它相等
else return get_kth_smallest(nums1, st1, sz1, nums2, st2 + k2, sz2, k-k2);
}
}
// 先按照主对角线反转, 再按照中垂线反转
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
swap(matrix[i][j], matrix[j][i]);
}
reverse(matrix[i].begin(), matrix[i].end());
}
}
双指针, 从前往后扫即可。
满足以下两点的就是平衡二叉树:
1.左右子树的高度差不能超过1
2.左右子树也是平衡二叉树
int IsBalance(BNode *root,int *pHeight) {
if(root == NULL) { *pHeight = 0; return 1; }
int leftHeight, rightHeight;
int leftBalance = IsBalance(root->left, &leftHeight);
int rightBalance = IsBalance(root->right, &leftHeight);
*pHeight = max(leftHeight, rightHeight) + 1;
if(leftBalance == 0 || rightBalance == 0) return 0;
if(abs(leftHeight - rightHeight) > 1) return 0;
return 1;
}
错排公式: D [ n ] = ( n − 1 ) ∗ ( D [ n − 1 ] + D [ n − 2 ] ) D[n] = (n - 1) * (D[n - 1] + D[n - 2]) D[n]=(n−1)∗(D[n−1]+D[n−2]),其中 D [ 1 ] = 0 , D [ 2 ] = 1 D[1] = 0, D[2] = 1 D[1]=0,D[2]=1, D [ n ] D[n] D[n] 表示 n个元素全部错排的方法数。
推导过程:
set<string> solve(int n) {
set<string> s; // 用set去重
if(n == 1) {
s.add("()");
return s;
}
else {
set<string> s2 = solve(n - 1);
for(string now : set2) {
s.add("()" + now);
s.add(now + "()");
s.add("(" + now + ")");
}
return s;
}
}
比如[5,1,3,4,5,1,3],答案是7 + 2 = 9
维护每一个柱子左右的最高柱子, 当前柱子的存水量就是 min(左最大值, 右最大值)。
单调栈 扫两遍
public class Singleton{
private static Singleton instance = null;
private(){
}
public static Singleton getInstance(){
if(instance = null) {
instance = new Singleton();
}
return instance;
}
}
归并排序
//参考紫书算法竞赛入门经典
void merge_sort(int *A, int l, int r, int *T){ //[l, r) 排序. 外部调用区间为[0, n)
if(r - l > 1){
int mid = l+(r-l)/2;
int p = l, q = mid, now = l;
// 对左右两部分区间分别归并排序
merge_sort(A, l, mid, T);
merge_sort(A, mid, r, T);
// 合并左右两部分
while(p < mid || q < r){
if(q >= r || (p < mid && A[p] <= A[q])){
T[now++] = A[p++];
}
else{
T[now++] = A[q++];
cnt += mid - p; // cnt记录的是逆序对个数
}
}
for(int i = l; i < r; i++) A[i] = T[i];
}
}
#include
using namespace std;
void Qsort(int a[], int low, int high)
{
if(low >= high) return;
int first = low;
int last = high;
int key = a[first];/*用字表的第一个记录作为枢轴*/
while(first < last)
{
while(first < last && a[last] >= key) last--;
a[first] = a[last];/*将比第一个小的移到低端*/
while(first < last && a[first] <= key) first++;
a[last] = a[first];
/*将比第一个大的移到高端*/
}
a[first] = key;/*枢轴记录到位*/
Qsort(a, low, first-1);
Qsort(a, first+1, high);
}
int main()
{
int a[] = {57, 68, 59, 52, 72, 28, 96, 33, 24};
Qsort(a, 0, sizeof(a) / sizeof(a[0]) - 1);/*这里原文第三个参数要减1否则内存越界*/
for(int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
cout << a[i] << "";
}
return 0;
}/*参考数据结构p274(清华大学出版社,严蔚敏)*/
用小根堆维护, 当前值大于队内最小值就替换。
include
#include
using namespace std;
void max_heapify(int arr[], int start, int end) {
//建立父节点指标和子节点指标
int dad = start;
int son = dad * 2 + 1;
while (son <= end) { //若子节点指标在范围内才做比较
if (son + 1 <= end && arr[son] < arr[son + 1]) //先比较两个子节点大小,选择最大的
son++;
if (arr[dad] > arr[son]) //如果父节点大於子节点代表调整完毕,直接跳出函数
return;
else { //否则交换父子内容再继续子节点和孙节点比较
swap(arr[dad], arr[son]);
dad = son;
son = dad * 2 + 1;
}
}
}
void heap_sort(int arr[], int len) {
//初始化,i从最後一个父节点开始调整
for (int i = len / 2 - 1; i >= 0; i--)
max_heapify(arr, i, len - 1);
//先将第一个元素和已经排好的元素前一位做交换,再从新调整(刚调整的元素之前的元素),直到排序完毕
for (int i = len - 1; i > 0; i--) {
swap(arr[0], arr[i]);
max_heapify(arr, 0, i - 1);
}
}
int main() {
int arr[] = { 3, 5, 3, 0, 8, 6, 1, 5, 8, 6, 2, 4, 9, 4, 7, 0, 1, 8, 9, 7, 3, 1, 2, 5, 9, 7, 4, 0, 2, 6 };
int len = (int) sizeof(arr) / sizeof(*arr);
heap_sort(arr, len);
for (int i = 0; i < len; i++)
cout << arr[i] << ' ';
cout << endl;
return 0;
}
#include
using namespace std;
int Partition(int* A,int left,int right){
int key=A[left];
while(left=key)
right--;
if(left
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MHAKF7vd-1585387853397)(/Users/dreamstart/Downloads/media/15516222282812.jpg)]
class Solution {
public:
int countDigitOne(int n) {
long long base = 1;
int count = 0;
while(base <= n){
int round = n / (base * 10);
int now = n / base % 10;
int after = n % base;
count += round * base;
if(now == 1) count += after + 1;
else if(now >= 2) count += base;
base *= 10;
}
return count;
}
};
le(left } int findKthNum(int* A,int left,int right,int k){ int main() } 在字符串 S 里面找出,包含 T 所有字母的最小子串。
right–;
if(left while(left
int index=Partition(A,left,right);
if(index+1==k)
return A[index];
else if(index+1
else
findKthNum(A,left,index-1,k);
}
{
int A[]={2,3,5,1,6,7,4};
int len=sizeof(A)/sizeof(A[0]);cout << findKthNum(A,0,len-1,7) << endl;
return 0;
#### 约瑟夫环
[外链图片转存中...(img-MHAKF7vd-1585387853397)]
#### 从1到n整数中1出现的次数
```c++
class Solution {
public:
int countDigitOne(int n) {
long long base = 1;
int count = 0;
while(base <= n){
int round = n / (base * 10);
int now = n / base % 10;
int after = n % base;
count += round * base;
if(now == 1) count += after + 1;
else if(now >= 2) count += base;
base *= 10;
}
return count;
}
};
LeetCode
[LeetCode76] 最小覆盖子串:滑动窗口
string minWindow(string s, string t) {
int S = s.size() - 1, T = t.size();
for(int i = 0; i < T; i++) vis[t[i]]++;
int l = 0, r = -1, cnt = 0, ans = S + 1, ansl = 0, ansr = -1;
while(l <= S) {
while(r < S && cnt < T) {
r++;
if(tmp[s[r]] < vis[s[r]]) cnt++;
tmp[s[r]]++;
}
if(cnt == T && r - l + 1 <= ans) ans = r - l + 1, ansl = l, ansr = r;
if(tmp[s[l]] <= vis[s[l]]) cnt--;
tmp[s[l]]--;
l++;
}
string str = "";
for(int i = ansl; i <= ansr; i++) str += s[i];
return str;
}
[LeetCode] Longest Increasing Path in a Matrix
[LeetCode面试题32I II III] 从上到下打印二叉树
// 按层 BFS即可
class Solution {
public:
vector<int> levelOrder(TreeNode* root) {
vector<int> ans;
if(root == NULL) return ans;
queue<TreeNode*> que;
TreeNode *cur = root;
que.push(cur);
while(!que.empty()) {
cur = que.front(); que.pop();
ans.push_back(cur->val);
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
return ans;
}
};
// BFS 过程中特殊处理每一行的节点
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int> > ans;
if(root == NULL) return ans;
TreeNode *cur = root;
queue<TreeNode*> que;
que.push(cur);
while(!que.empty()) {
vector<int> now;
int S = que.size(); // que.size() 就是当前深度的节点数
for(int i = 0; i < S; i++) {
cur = que.front(); que.pop();
now.push_back(cur->val);
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
ans.push_back(now);
}
return ans;
}
};