汉诺塔问题
汉诺塔问题中,3个圆盘至少需要移动7次,移动n个圆盘至少需要操作次
分治实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| void hanoi(int num, int sou, int tar, int aux){ static int i=1; if(num == 1){ printf("第%d次:从%c移动至%c\n", i, sou, tar); i++; } else{ hanoi(num-1, sou, aux, tar); printf("第%d次:从%c移动至%c\n", i, sou, tar); i++; hanoi(num-1, aux, tar, sou); } } int main(){ hanoi(3, 'A', 'B', 'C'); }
|
链表问题
链表翻转【双指针】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| ListNode* reverseList(ListNode* head) { if(!head||!head->next) return head; auto a=head, b=head->next; while(b){ auto c = b->next; b->next = a; a = b, b = c; } head->next = NULL; return a; }
ListNode* reverseList(ListNode* head) { if(!head||!head->next) return head; auto tail = reverseList(head->next); head->next->next = head; head->next = NULL; return tail; }
|
🍕 链表局部翻转(与上题对比【头插法】)
1.dummy; 2.头插法; 3.循环
【点我跳转>_<】
链表中的节点每k个一组翻转
链表尾到头逆序输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| vector<int> printListReversingly(ListNode* head) { vector<int> res; while(head){ res.insert(res.begin(), head->val); head=head->next; } return res; }
vector<int> printListReversingly(ListNode* head) { if(!head) return {}; auto res = printListReversingly(head->next); res.push_back(head->val); return res; }
|
O(1)时间删除节点
删除重复节点
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| ListNode* deleteDuplication(ListNode* head) { auto dummy = new ListNode(-1); dummy->next = head; auto p=dummy; while(p->next){ auto q = p->next; while(q && p->next->val==q->val) q = q->next; if(p->next->next==q) p=p->next; else p->next=q; } return dummy->next; }
|
删除倒数第k个节点
1 2 3 4 5 6 7 8
| ListNode* findKthToTail(ListNode* head, int k) { int n = 0; for(auto p = pListHead; p; p=p->next) n++; if(n<k) return nullptr; auto p=pListHead; for(int i=0; i<n-k; i++) p=p->next; return p; }
|
🍤链表中环的入口
Key:
- 让$second$从相遇点回退$y$步
- $first$:只可能在走第一圈时就碰到$second$
- $second$:碰到$first$时:走了$2x+2y$;在$first$刚进环时:走了$2x$, 距离环入口$y$,距离$first$ $2y$
- 推导: $x+y=nc,c=2\pi r$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| ListNode *entryNodeOfLoop(ListNode *head) { auto i = head, j = head; while(i && j){ i = i->next; j = j->next; if(j) j=j->next; else break; if(i == j){ i = head; while(i!=j) i = i->next, j = j->next; return i; } } return NULL; }
|
合并链表
找出两个链表的第一个公共节点
- 相遇:走过的距离
a+c+b = b+c+a
- 没有相遇:距离
a+b = b+a
- 类似追及相遇问题 原题链接
二叉搜索树与双向链表
二叉树问题
二叉树的镜像
1 2 3 4 5 6
| void mirror(TreeNode* root){ if(!root) return; mirror(root->left); mirror(root->right); swap(root->left, root->right); }
|
重建二叉树
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| map<int, int> hash;
TreeNode* dfs(vector<int>& preorder, vector<int>& inorder, int pl, int pr, int il, int ir){ if(pl > pr) return NULL; TreeNode* root = new TreeNode(preorder[pl]); int k = hash[preorder[pl]] - il; root->left = dfs(preorder, inorder, pl+1, pl+k, il, il+k-1); root->right = dfs(preorder, inorder, pl+k+1, pr, il+k+1, ir); return root; }
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { int len = preorder.size(); if(!len) return NULL; for(int i=0; i<len; i++) hash[inorder[i]] = i; return dfs(preorder, inorder, 0, len-1, 0, len-1); }
|