排序
快速排序
arr [ n ]
以arr[0]为基准,将小于arr[0]的放在arr[0]的左边,将大于arr[0]的放在arr[0]右边
i 从 1~n-1
j从 n-1~1
while(true){
找到第一个 arr[i]>arr[0]
找到第一个 arr[j]<arr[0]
i<=j 交换 i,j
}
归并排序
二叉树
二叉树的遍历具有框架性
前序、中序、后续遍历等就像深度优先遍历
层次遍历就像广度优先遍历
前序遍历
void traverse(TreeNode root){
if(root==null){
return ;
}
// do something
traverse(root.left);
traverse(root.right);
}
中序遍历
void traverse(TreeNode root){
if(root==null){
return ;
}
traverse(root.left);
// do something
traverse(root.right);
}
后续遍历
void traverse(TreeNode root){
if(root==null){
return ;
}
traverse(root.left);
traverse(root.right);
// do something
}
层次遍历
不区分层数
Queue<TreeNode> queue = new LinkedList<>();
// root入队
queue.offer(root);
while(!queue.isEmpty()){
// root出队
TreeNode current = queue.poll();
// 当前层 do something
System.out.println(current.val);
// 加入下一层元素
queue.offer(current.left);
queue.offer(current.right);
}
可区分层数
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(pRoot);
while(!queue.isEmpty()){
// 当前层元素个数
int size = queue.size();
while(size>0){
// 便利当前层每一个元素
TreeNode node = queue.poll();
size --;
// do something
queue.offer(node.left);
queue.offer(node.right);
}
}
动态规划—dp数组
DP三步骤:
1)确定状态转移方程,如:dp[i]与dp[i-1]之间关系
2)确定初始状态,如:dp[0] = 0,dp[1] = 1
3)遍历并且构造出dp数组和对应下标的值
4)根据dp数组得到最终的答案
一维dp
二维dp
0-1背包问题 物品i,价值v[i],重量w[i],能背的重量j
dp[i][j] 前i个物品下,重量j的约束下能达到的最大价值
dp[i][j] = max()
图
最短路径
Dijkstra算法
掌握一个思路,dp[i] 表示起始节点0到终点i的最短路径
每次找到dp[i]中未访问过的最小值,将之标记为已经访问
与dp[i] 连通的节点 j 算出 dp[j] = Math.min(dp[j], dp[i]+graph[i][j])
直到再也找不到dp[i] 中未访问过的最小值,就全部遍历结束,能够得到点0到1~n-1所有节点的最短路径dp[i]
public int findShortestPath (int n, int m, int[][] graph) {
int [] visited = new int[n];
int [][] myGraph = new int[n][n];
int[] dp = new int[n];
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
myGraph[i][j] = Integer.MAX_VALUE;
}
myGraph[i][i] = 0;
dp[i] = Integer.MAX_VALUE;
}
for(int i=0;i<graph.length;i++){
myGraph[graph[i][0]-1][graph[i][1]-1] = Math.min(graph[i][2],myGraph[graph[i][0]-1][graph[i][1]-1]);
myGraph[graph[i][1]-1][graph[i][0]-1] = Math.min(graph[i][2],myGraph[graph[i][1]-1][graph[i][0]-1]);
}
dp[0] = 0;
while(true){
int index = findMinIndex(visited,dp);
if(index == -1){
break;
}
visited[index] = 1;
for(int j=0;j<n;j++){
if( myGraph[index][j] != Integer.MAX_VALUE ){
dp[j] = Math.min(dp[index] + myGraph[index][j],dp[j]);
}
}
}
if(dp[n-1]!=Integer.MAX_VALUE){
return dp[n-1];
}else{
return -1;
}
}
int findMinIndex(int [] visited,int [] dp){
int len = dp.length;
int min = Integer.MAX_VALUE;
int minIndex = -1;
for(int i=0;i<len;i++){
if(dp[i] < min && visited[i]==0){
min = dp[i];
minIndex = i;
}
}
return minIndex;
}
并查集
树可以看成是一个连通且 无环 的 无向 图。
给定往一棵 n 个节点 (节点值 1~n) 的树中添加一条边后的图。添加的边的两个顶点包含在 1 到 n 中间,且这条附加的边不属于树中已存在的边。图的信息记录于长度为 n 的二维数组 edges ,edges[i] = [ai, bi] 表示图中在 ai 和 bi 之间存在一条边。
请找出一条可以删去的边,删除后可使得剩余部分是一个有着 n 个节点的树。如果有多个答案,则返回数组 edges 中最后出现的那个。
class Solution {
public int[] findRedundantConnection(int[][] edges) {
int n = edges.length;
int[] parent = new int[n + 1];
// 初始化并查集数组 parent[i] = i
for (int i = 1; i <= n; i++) {
parent[i] = i;
}
for (int i = 0; i < n; i++) {
int[] edge = edges[i];
int node1 = edge[0], node2 = edge[1];
if (find(parent, node1) != find(parent, node2)) {
union(parent, node1, node2);
} else {
// 当发现边对应的两个顶点已经在同一个集合了,再次union的话,会形成环,因此去掉这条边
return edge;
}
}
return new int[0];
}
// parent[index1的root点] = index2的root点
public void union(int[] parent, int index1, int index2) {
parent[find(parent, index1)] = find(parent, index2);
}
// 查询节点index的root点
public int find(int[] parent, int index) {
if (parent[index] != index) {
parent[index] = find(parent, parent[index]);
}
return parent[index];
}
}