69. Binary Tree Level Order Traversal: 点击打开链接
Time: O(n)
/**
* Definition of TreeNode:
* public class TreeNode {
* public int val;
* public TreeNode left, right;
* public TreeNode(int val) {
* this.val = val;
* this.left = this.right = null;
* }
* }
*/
public class Solution {
/**
* @param root: The root of binary tree.
* @return: Level order a list of lists of integer
*/
public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) {
ArrayList<ArrayList<Integer>> result=new ArrayList<>();
if(root==null){
return result;
}
Queue<TreeNode> queue=new LinkedList<>();
queue.offer(root); //先把root的值放入
while(!queue.isEmpty()){ //每次while循环的时候都是前一层节点加入后进行的
ArrayList<Integer> level=new ArrayList<>();
int size=queue.size();
for(int i=0;i<size;i++){ //加入每层的结点,同时拿到下一层的结点加入queue里,使得while循环不为空
TreeNode cur=queue.poll();
level.add(cur.val);
if(cur.left!=null){ //拿下一层的节点
queue.offer(cur.left);
}
if(cur.right!=null){
queue.offer(cur.right);
}
}
result.add(level);
}
return result;
}
}
71.Binary Tree Zigzag Level Order Traversal: 点击打开链接
/**
* Definition of TreeNode:
* public class TreeNode {
* public int val;
* public TreeNode left, right;
* public TreeNode(int val) {
* this.val = val;
* this.left = this.right = null;
* }
* }
*/
public class Solution {
/**
* @param root: The root of binary tree.
* @return: A list of lists of integer include
* the zigzag level order traversal of its nodes' values
*/
public ArrayList<ArrayList<Integer>> zigzagLevelOrder(TreeNode root) {
ArrayList<ArrayList<Integer>> result=new ArrayList<>();
if(root==null){
return result;
}
Queue<TreeNode> queue=new LinkedList<>();
queue.offer(root);
boolean rightOrder=true; //只需要这边多个flag来指示每层的顺序是从左向右,还是从右向左
while(!queue.isEmpty()){
ArrayList<Integer> level=new ArrayList<>();
int size=queue.size();
for(int i=0;i<size;i++){
TreeNode cur=queue.poll();
if(rightOrder){
level.add(cur.val);
}else{
level.add(0,cur.val); //ArrayList这个方法是给添加的元素指定位置,这里指定位置为最前面
}
if(cur.left!=null){
queue.add(cur.left);
}
if(cur.right!=null){
queue.add(cur.right);
}
}
result.add(level); //还有一种方法是每次添加到result前,
rightOrder=!rightOrder; //根据flag判断 Collections.reverse(level);
}
return result;
}
}
281. Zigzag Iterator - LeetCode
note:感觉是我找到的参考中最好的解答方法,简洁易懂,queue的很好练习
public class ZigzagIterator {
Queue<Integer> queue = new LinkedList<>();
public ZigzagIterator(List<Integer> v1, List<Integer> v2) {
int len = Math.min(v1.size(), v2.size());
for(int i=0; i<len; i++)
{
queue.offer(v1.get(i));
queue.offer(v2.get(i));
}
if(v1.size()>v2.size())
{
for(int i=len; i<v1.size(); i++)
{
queue.offer(v1.get(i));
}
}
else{
for(int i=len; i<v2.size(); i++)
{
queue.offer(v2.get(i));
}
}
}
public int next() {
return queue.poll();
}
public boolean hasNext() {
return !queue.isEmpty();
}
}
/**
* Your ZigzagIterator object will be instantiated and called as such:
* ZigzagIterator i = new ZigzagIterator(v1, v2);
* while (i.hasNext()) v[f()] = i.next();
*/
7. Binary Tree Serialization and Derialization: 点击打开链接
1
/ \
2 3
思路:序列化为:1,2,#,#,3,#,#
/**
* Definition of TreeNode:
* public class TreeNode {
* public int val;
* public TreeNode left, right;
* public TreeNode(int val) {
* this.val = val;
* this.left = this.right = null;
* }
* }
*/
class Solution {
public String serialize(TreeNode root) { //序列化
return serial(new StringBuilder(), root).toString();
}
private StringBuilder serial(StringBuilder sb, TreeNode root) {
if (root == null) {
return sb.append("#").append(",");
}else{
sb.append(root.val).append(",");
}
serial(sb, root.left);
serial(sb, root.right);
return sb;
}
public TreeNode deserialize(String data) { //反序列化
return deserial(new LinkedList<>(Arrays.asList(data.split(","))));
}
private TreeNode deserial(Queue<String> queue) { //建树的过程
String val = queue.poll();
if ("#".equals(val)) return null;
TreeNode root = new TreeNode(Integer.valueOf(val));
root.left = deserial(queue);
root.right = deserial(queue);
return root;
}
}
178.Graph Valid Tree: 点击打开链接
思路:以n=5, edges={{0,1}, {0,2}, {0,3}, {1,4}}为例:
1. 初始化图: {0=[1, 2, 3],1=[0, 4],2=[0],3=[0],4=[1]}
2. 对graph里的每一个value进行判断,如果这些value去重后最后的集合是key的集合{0,1,2,3,4},就是树。
注意:图是一棵树需要满足两个条件:n-1=边的条数,n个点连通
所以要判断两步:
- 判断边的条数是不是等于n-1
- 判断从一点出发(任意一点),是不是能连通另外所有的点
public class Solution {
/**
* @param n an integer
* @param edges a list of undirected edges
* @return true if it's a valid tree, or false
*/
public boolean validTree(int n, int[][] edges) {
if(n==0){
return false;
} //图是一棵树要满足两个条件:
if(edges.length!=n-1){ //条件1:n-1=边的条数
return false;
}
Map<Integer, Set<Integer>> graph=initializeGraph(n,edges);
Queue<Integer> queue=new LinkedList<>();
Set<Integer> set=new HashSet<>();
queue.offer(0);
set.add(0);
while(!queue.isEmpty()){
int node=queue.poll();
for(Integer neighbor: graph.get(node)){ //就是把所有连通的点放在set里的过程,最后用条件2判断
if(set.contains(neighbor)){ //每次往set里放之前都要先判断是不是已经存在于set里
continue; //如果已经在了,continue掉当前neighbor,查看下一个 }
set.add(neighbor);
queue.offer(neighbor);
}
}
// 就是要看从一点出发,是不是能找到其余所有的点
return set.size()==n; //条件2:n个点连通(也就是没有零星节点在连着的集体外面)
}
//EX. [[0,1],[0,2],[0,3],[1,4]], 对于点1,map的key是1,set是{0,4}
private Map<Integer, Set<Integer>> initializeGraph(int n, int[][] edges){
Map<Integer, Set<Integer>> graph=new HashMap<>(); //map装的是<每个点,和每个点相邻的边的另外连着的点的集合set>
for(int i=0;i<n;i++){
graph.put(i, new HashSet<Integer>()); //先把map里装上<每个点,<>>, 空set是将要装满足条件的点的
}
for(int i=0;i<edges.length;i++){ //graph用二维数组表示
int a=edges[i][0]; //整个操作就是装map
int b=edges[i][1];
graph.get(a).add(b);
graph.get(b).add(a);
}
return graph;
}
}
323. Number of Connected Components in an Undirected Graph
Given n
nodes labeled from 0
to n - 1
and a list of undirected edges (each edge is a pair of nodes), write a function to find the number of connected components in an undirected graph.
Example 1:
0 3
| |
1 --- 2 4
Given n = 5
and edges = [[0, 1], [1, 2], [3, 4]]
, return 2
.
Example 2:
0 4
| |
1 --- 2 --- 3
Given n = 5
and edges = [[0, 1], [1, 2], [2, 3], [3, 4]]
, return 1
.
You can assume that no duplicate edges will appear in edges
. Since all edges are undirected, [0, 1]
is the same as [1, 0]
and thus will not appear together in edges
.
思路:遍历n里的每一个点,如果点不在visited HashSet里,就有一个component,然后bfs这个component找到这一块的所有连通点
注意:很多情况下都是Queue和HashSet连在一起用的,HashSet可以在整体上帮助判断当前点有没有被遍历过
class Solution {
public int countComponents(int n, int[][] edges) {
Map<Integer,Set<Integer>> map=getGraph(n,edges);
HashSet<Integer> visited = new HashSet<>();
int count = 0;
for(int i=0;i<n;i++){
if(!visited.contains(i)){ //一开始visited的size是0, 所以只有一个连通块的情况就是从这里入口,进行宽搜,后面遍历到的所有元素,都是set里
count++;
bfs(map,i,visited); //哪个元素不在set里,就用那个元素做为入口,把这个元素所在的连通块里的所有元素都加入set里
}
}
return count;
}
// 所以这个题从始至终,只有一个set,无论几个连通块进行各自的bfs, 都加入这个set里
private void bfs(Map<Integer,Set<Integer>> map, int i, Set<Integer> visited){
Queue<Integer> q = new LinkedList<>();
q.offer(i);
visited.add(i);
while(!q.isEmpty()){
int curr = q.poll();
for(int neighbor : map.get(curr)){
if(!visited.contains(neighbor)){
q.offer(neighbor);
visited.add(neighbor);
}
}
}
}
private Map<Integer,Set<Integer>> getGraph(int n,int[][] edges){
Map<Integer,Set<Integer>> map=new HashMap<>();
for(int i=0;i<n;i++){
map.put(i,new HashSet<Integer>());
}
for(int i=0;i<edges.length;i++){
int a=edges[i][0];
int b=edges[i][1];
map.get(a).add(b);
map.get(b).add(a);
}
return map;
}
}
137. Clone Graph: 点击打开链接
/**
* Definition for undirected graph.
* class UndirectedGraphNode {
* int label;
* ArrayList<UndirectedGraphNode> neighbors;
* UndirectedGraphNode(int x) {
* label = x;
* neighbors = new ArrayList<UndirectedGraphNode>();
* }
* };
*/
public class Solution {
/**
* @param node: A undirected graph node
* @return: A undirected graph node
*/
public UndirectedGraphNode cloneGraph(UndirectedGraphNode node) {
if(node==null){
return node;
}
ArrayList<UndirectedGraphNode> nodes=getNodes(node); //拿到所有和node连接点
Map<UndirectedGraphNode, UndirectedGraphNode> mapping=new HashMap<>(); //map是新老节点的映射<老节点,新克隆的节点>
for(UndirectedGraphNode n : nodes){ //克隆每一个点
//因为题目给定的UndirectedGraphNode类的neighbors属性是constructor一加载,自动new ArrayList<>()
//所以这边要注意new实例时的小细节
mapping.put(n, new UndirectedGraphNode(n.label));
}
for(UndirectedGraphNode n : nodes){ //克隆每一条边
UndirectedGraphNode newNode=mapping.get(n);
for(UndirectedGraphNode neighbor : n.neighbors){
UndirectedGraphNode newNeighbor=mapping.get(neighbor);
newNode.neighbors.add(newNeighbor);
}
}
return mapping.get(node); //return的就是和老节点对应的新节点node
}
private ArrayList<UndirectedGraphNode> getNodes(UndirectedGraphNode node){ //通过一个点找到这个点的所有连通点
Queue<UndirectedGraphNode> queue=new LinkedList<>();
Set<UndirectedGraphNode> set=new HashSet<>();
queue.offer(node);
set.add(node);
while(!queue.isEmpty()){
UndirectedGraphNode head=queue.poll();
for(UndirectedGraphNode neighbor:head.neighbors){
if(!set.contains(neighbor)){
set.add(neighbor);
queue.offer(neighbor);
}
}
}
return new ArrayList<UndirectedGraphNode>(set);
}
}
618. Search Graph Nodes: 点击打开链接
/**
* Definition for graph node.
* class UndirectedGraphNode {
* int label;
* ArrayList<UndirectedGraphNode> neighbors;
* UndirectedGraphNode(int x) {
* label = x; neighbors = new ArrayList<UndirectedGraphNode>();
* }
* };
*/
public class Solution {
/**
* @param graph a list of Undirected graph node
* @param values a hash mapping, <UndirectedGraphNode, (int)value>
* @param node an Undirected graph node
* @param target an integer
* @return the a node
*/
public UndirectedGraphNode searchNode(ArrayList<UndirectedGraphNode> graph, //gragh参数是多余的
Map<UndirectedGraphNode, Integer> values,
UndirectedGraphNode node, //因为通过这一点可以访问到其他的点
int target) {
Queue<UndirectedGraphNode> queue=new LinkedList<>();
Set<UndirectedGraphNode> set=new HashSet<>();
queue.offer(node);
set.add(node);
while(!queue.isEmpty()){
UndirectedGraphNode curNode=queue.poll();
if(values.get(curNode)==target){ //用queue遍历,先拿到的点一定是离当前点最近的
return curNode;
}
for(UndirectedGraphNode neighbor:curNode.neighbors){
if(!set.contains(neighbor)){
set.add(neighbor);
queue.offer(neighbor);
}
}
}
return null;
}
}
127.Topological Sort: 点击打开链接
/**
* Definition for Directed graph.
* class DirectedGraphNode {
* int label;
* ArrayList<DirectedGraphNode> neighbors;
* DirectedGraphNode(int x) { label = x; neighbors = new ArrayList<DirectedGraphNode>(); }
* };
*/
public class Solution {
/**
* @param graph: A list of Directed graph node
* @return: Any topological order for the given graph.
*/
public ArrayList<DirectedGraphNode> topSort(ArrayList<DirectedGraphNode> graph) {
ArrayList<DirectedGraphNode> result=new ArrayList<>();
if(graph==null){
return result;
}
Map<DirectedGraphNode,Integer> indegree=getIndegree(graph); //拿到整个图上所有点和每点对应的入度映射
Queue<DirectedGraphNode> queue=new LinkedList<>();
for(DirectedGraphNode node:graph){ //这边要有个判断,indegree为0的首先进queue
if(indegree.get(node)==0){
queue.offer(node);
result.add(node);
}
}
while(!queue.isEmpty()){
DirectedGraphNode curNode=queue.poll(); //只要有点从queue里poll出
for(DirectedGraphNode neighbor:curNode.neighbors){ //就要把此点的所有邻居点的indegree-1
indegree.put(neighbor,indegree.get(neighbor)-1); //因为此点被删,所有的邻居点的入度都要减少1
if(indegree.get(neighbor)==0){
queue.offer(neighbor);
result.add(neighbor);
}
}
}
return result;
}
private Map<DirectedGraphNode,Integer> getIndegree(ArrayList<DirectedGraphNode> graph){
Map<DirectedGraphNode,Integer> map=new HashMap<>(); //得到graph里每一个node的入度indegree
for(DirectedGraphNode node:graph){ //先初始化graph里每一个node,使得入度是0
map.put(node,0);
}
for(DirectedGraphNode node:graph){
for(DirectedGraphNode neighbor:node.neighbors){ //然后再对每个node的邻居点算入度
map.put(neighbor,map.get(neighbor)+1);
}
}
return map;
}
}
615. Course Schedule: 点击打开链接
以numCourses=5, prerequisites={{1,0}, {2,0}, {4,2}, {4,1}}为例:
public class Solution {
/**
* @param numCourses a total of n courses
* @param prerequisites a list of prerequisite pairs
* @return true if can finish all courses or false
*/
public boolean canFinish(int numCourses, int[][] prerequisites) {
List<Integer>[] neighbors=new ArrayList[numCourses]; //List数组[null,null,null,null,null]
int[] degree=new int[numCourses]; //每个课程的入度数组[0,0,0,0,0]
for(int i=0;i<neighbors.length;i++){ //初始化List数组[[],[],[],[],[]]
neighbors[i]=new ArrayList<>();
}
for(int i=0;i<prerequisites.length;i++){ //prerequisites[i][0]或是prerequisites[i][1]表示每一个课程
degree[prerequisites[i][0]]++; //[0,1,1,0,2]
neighbors[prerequisites[i][1]].add(prerequisites[i][0]); //[[1,2],[4],[4],[],[]]
}
Queue<Integer> queue=new LinkedList<>();
for(int i=0;i<degree.length;i++){
if(degree[i]==0){
queue.offer(i);
}
}
int resultNum=0;
while(!queue.isEmpty()){
int course=queue.poll(); //每一个检测完的的课程都要删掉
resultNum++; //然后检测的结果数+1
int size=neighbors[course].size(); //针对刚才删掉的课程对它的邻居课程List进行判断
for(int i=0;i<size;i++){
int neighbor=neighbors[course].get(i); //拿到邻居课程的每一个课程,List里的每一个小List里的内容
degree[neighbor]--; //在邻居课程里的每一个课程的入度都要-1
if(degree[neighbor]==0){ //再判断入度-1后是否有课程满足条件:入度为0
queue.offer(neighbor); //如果满足条件,再循环检测
}
}
}
return resultNum==numCourses; //最后的判断很关键,检测的结果数==课程总数
}
}
598.Zombie in Matrix : 点击打开链接
矩阵中的BFS的代表题型,而且此题是一个完整的BFS,具有三层。
class Coordinate{
int x,y;
public Coordinate(int x,int y){
this.x=x;
this.y=y;
}
}
public class Solution {
public int[] deltaX = {1, 0, 0, -1}; //四个方向的坐标变换数组形式
public int[] deltaY = {0, 1, -1, 0};
/**
* @param grid a 2D integer grid
* @return an integer
*/
public int zombie(int[][] grid) {
if (grid == null || grid.length == 0) {
return 0;
}
int people = 0; //遍历整个matrix
Queue<Coordinate> queue = new LinkedList<>();
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == 0) { //拿到people的个数,后面根据people==0来具体判断
people++;
} else if (grid[i][j] == 1) {
queue.offer(new Coordinate(i, j)); //遍历过程中所有zombie的坐标放到queue里
}
}
}
if (people == 0) { //corner case
return 0;
}
int days = 0; //每一圈(每一层),也就是一天
while (!queue.isEmpty()){
days++;
int size = queue.size();
for (int i = 0; i < size; i++){
Coordinate zombie = queue.poll(); //对于queue里的每一个删除的zombie,都要对它的外一层判断
for (int direction = 0; direction < 4; direction++) {
Coordinate neighbor = new Coordinate( //外一层有四个点
zombie.x + deltaX[direction],
zombie.y + deltaY[direction]
);
if(isPeople(neighbor, grid)){ //如果四个点中有是people的
grid[neighbor.x][neighbor.y] = 1; //就会被咬成zombie
people--; //同时people的个数-1
if (people == 0) { //如果没有people了,过程就结束了,返回所需天数
return days;
}
queue.offer(neighbor);
}
}
}
}
return -1;
}
private boolean isPeople(Coordinate coor, int[][] grid) {
if (coor.x < 0 || coor.x >= grid.length) { //在遍历是不是isPeopleP过程中,要对出界的情况进行处理
return false;
}
if (coor.y < 0 || coor.y >= grid[0].length) {
return false;
}
return (grid[coor.x][coor.y] ==0);
}
}
611.Knight Shortest Path : 点击打开链接
/**
* Definition for a point.
* public class Point {
* publoc int x, y;
* public Point() { x = 0; y = 0; }
* public Point(int a, int b) { x = a; y = b; }
* }
*/
public class Solution {
/**
* @param grid a chessboard included 0 (false) and 1 (true)
* @param source, destination a point
* @return the shortest path
*/
public int[] deltaX={1,1,-1,-1,2,2,-2,-2}; //坐标变换数组:马走日
public int[] deltaY={2,-2,2,-2,1,-1,1,-1};
public int shortestPath(boolean[][] grid, Point source, Point destination) {
if(grid==null || grid.length==0){
return -1;
}
Queue<Point> queue=new LinkedList<>();
queue.offer(source);
int steps=0;
while(!queue.isEmpty()){
int size=queue.size();
for(int i=0;i<size;i++){
Point point=queue.poll();
if(point.x==destination.x && point.y==destination.y){
return steps;
}
for(int direction=0;direction<8;direction++){
Point movePoint=new Point(point.x+deltaX[direction],
point.y+deltaY[direction]);
if(isValid(grid, movePoint)){ //如果是有效点,就添加到queue
queue.offer(movePoint); //因为下一轮马要从queue里poll出的点出发走下一步
grid[movePoint.x][movePoint.y]=true;//同时添加到queue里的点要做标记
}
}
}
steps++;
}
return -1;
}
private boolean isValid(boolean[][] grid, Point point){ //拿到有效点,并赋值为false返回供部分需要点标记为true
if (point.x < 0 || point.x >= grid.length) { //出边界的点
return false;
}
if (point.y < 0 || point.y >= grid[0].length) {
return false;
}
return grid[point.x][point.y] == false; //其实这个函数起名有歧义
}
}
690. Employee Importance (LeetCode)
/*
// Employee info
class Employee {
// It's the unique id of each node;
// unique id of this employee
public int id;
// the importance value of this employee
public int importance;
// the id of direct subordinates
public List<Integer> subordinates;
};
*/
class Solution {
public int getImportance(List<Employee> employees, int id) {
int nImportance = 0;
for(Employee e : employees)
{
if (e.id == id)
{
if (e.subordinates.size()==0)
{
return e.importance;
}
nImportance += e.importance;
for(Integer n : e.subordinates)
{
nImportance += getImportance(employees, n);
}
}
}
return nImportance;
}
}
/*
// Employee info
class Employee {
// It's the unique id of each node;
// unique id of this employee
public int id;
// the importance value of this employee
public int importance;
// the id of direct subordinates
public List<Integer> subordinates;
};
*/
class Solution {
public int getImportance(List<Employee> employees, int id) {
int nImportance = 0;
// <Id, Employee>
Map<Integer, Employee> map = new HashMap<>(); //map的设计很到位
for(Employee e : employees)
{
map.put(e.id, e);
}
Queue<Integer> queue = new LinkedList<>();
queue.offer(id);
while(!queue.isEmpty())
{
Employee e = map.get(queue.poll()); //queue与map的精妙结合
nImportance += e.importance;
List<Integer> subordinates = e.subordinates;
for(Integer sub : subordinates)
{
queue.offer(sub);
}
}
return nImportance;
}
}