bfs 宽度优先搜索
bfs : 树的bfs+图的bfs
总体的思想:
- 初始化(queue+vistied)
- 不断的访问队列:每次pop出来队列的一个点
扩展:访问邻居的结点node.neigbors 也就是下一层的结点,符合要求的加入到队列里
作为层层遍历的一种数据结构,第一次找到的点一定是最短的路径。
1.二叉树或者图的宽度优先搜索
2.建立一个visted 用来记录遍历访问过的结点 以至于不重复的访问。走回头路。如果是有向的图那么就不需要这个set集合。因为不会走回头路!数据从做到右的遍历是有顺序的。
3.建立Deque deque = new ArrayDeque<>();// 每一层的结点,即将要访问的下一层的邻居结点
这里需要注意的是可以用当前的deque的size来表示要当前的层的结点数。 有的题目用length记录遍历到第几层。此时就需要用deque的当前size来作为一个分割的结点。
Number of Islands
这个题就是相当于图的遍历找到要遍历的符合要求的邻居结点。用bfs一层一层的遍历直到没有可以遍历的结点算是一个联通块,接着traverse的结点作为起点继续bfs找联通块
Description
Given a boolean 2D matrix, 0 is represented as the sea, 1 is represented as the island. If two 1 is adjacent, we consider them in the same island. We only consider up/down/left/right adjacent.
Find the number of islands.
Example
Example 1:
Input:
[
[1,1,0,0,0],
[0,1,0,0,1],
[0,0,0,1,1],
[0,0,0,0,0],
[0,0,0,0,1]
]
Output:
3
Example 2:
Input:
[
[1,1]
]
Output:
1
`
class Coordinate {
int x;
int y;
public Coordinate(int x,int y){
this.x = x;
this.y = y;
}
}
public class Solution {
/**
* @param grid: a boolean 2D matrix
* @return: an integer
*/
int[] deltaX = {0,1,-1,0};
int[] deltaY = {1,0,0,-1};
public int numIslands(boolean[][] grid) {
// write your code here
if(grid == null || grid.length == 0){
return 0;
}
int row = grid.length;
int col = grid[0].length;
int numIslands = 0;
boolean[][] visited = new boolean[row][col];
for (int i = 0; i < row; i++) {
for (int j = 0; j < col; j++) {
if(grid[i][j]&& visited[i][j]== false){
System.out.println("开始遍历的起点:("+i+","+j+")");
bfs(grid,i,j,visited);
numIslands++;
}
}
}
return numIslands;
}
private void bfs(boolean[][] grid,int x,int y,boolean[][] visited){
Queue <Coordinate> queue = new ArrayDeque<> ();
queue.offer(new Coordinate(x,y));
visited[x][y] = true;
while(!queue.isEmpty()){
Coordinate node = queue.poll();
for(int direction = 0; direction < 4;direction++){
int neiborhoodX = node.x + deltaX[direction];
int neiborhoodY = node.y + deltaY[direction];
if(!isValid(neiborhoodX, neiborhoodY, grid,visited)){
continue;
}
Coordinate newNode = new Coordinate(neiborhoodX,neiborhoodY);
queue.offer(newNode);
visited[neiborhoodX][neiborhoodY] = true;
}
}
}
private boolean isValid(int x,int y,boolean[][] grid,boolean[][] visited){
int row = grid.length;
int col = grid[0].length;
if(x < 0 || x >= row || y < 0 || y >= col){
return false;
}
if(visited[x][y]){
return false;
}
return grid[x][y];
}
}
`
Knight Shortest Path
Description
Given a knight in a chessboard (a binary matrix with 0 as empty and 1 as barrier) with a source position, find the shortest path to a destination position, return the length of the route.
Return -1 if destination cannot be reached.
source and destination must be empty.
Knight can not enter the barrier.
Path length refers to the number of steps the knight takes.
If the knight is at (x, y), he can get to the following positions in one step:
(x + 1, y + 2)
(x + 1, y - 2)
(x - 1, y + 2)
(x - 1, y - 2)
(x + 2, y + 1)
(x + 2, y - 1)
(x - 2, y + 1)
(x - 2, y - 1)
Example
Example 1:
Input:
[[0,0,0],
[0,0,0],
[0,0,0]]
source = [2, 0] destination = [2, 2]
Output: 2
Explanation:
[2,0]->[0,1]->[2,2]
Example 2:
Input:
[[0,1,0],
[0,0,1],
[0,0,0]]
source = [2, 0] destination = [2, 2]
Output:-1
``
/**
* Definition for a point.
* class Point {
* int x;
* int y;
* Point() { x = 0; y = 0; }
* Point(int a, int b) { x = a; y = b; }
* }
*/
public class Solution {
/**
* @param grid: a chessboard included 0 (false) and 1 (true)
* @param source: a point
* @param destination: a point
* @return: the shortest path
*/
public int shortestPath(boolean[][] grid, Point source, Point destination) {
// write your code here
//corner case
if(grid == null || grid.length == 0 || source == null || destination == null){
return -1;
}
int col = grid[0].length;
int[] destinationX = {1, 2,2,1,-1,-2,-2,-1};
int[] destinationY = {-2,-1,1,2,2 ,1 ,-1,-2};
Queue<Point> queue = new ArrayDeque();
Map<Integer,Integer> cellToDisMap = new HashMap();
queue.offer(source);
cellToDisMap.put(convert(source.x,source.y,col), 0);//marked vistied
while(!queue.isEmpty()){
Point point = queue.poll();
Integer currentPoint = convert(point.x,point.y,col);
// arrived at destination
if(point.x == destination.x && point.y == destination.y){
return cellToDisMap.get(currentPoint);
}
// go through it's 8 neighboors here
for (int direction = 0; direction < 8; direction++){
int newX = point.x+destinationX[direction];
int newY = point.y+destinationY[direction];
if(!isValid(newX,newY,grid,cellToDisMap)){
continue;
}
int newPoint = convert(newX, newY, col);
queue.offer(new Point(newX,newY));
cellToDisMap.put(newPoint,cellToDisMap.get(currentPoint)+1);//marked
}
}
return -1;
}
public boolean isValid(int newX,int newY,boolean[][] grid,Map<Integer,Integer> cellTodisMap){
int row = grid.length;
int col = grid[0].length;
if(newX<0||newX>=row||newY<0||newY>=col){
return false;
}
if(cellTodisMap.containsKey(convert(newX, newY, col))){
return false;
}
//return !grid[newX][newY];
//if cell is 0 means false return "valid" = true
// so this case means is valid
if(grid[newX][newY] == false){
return true;
}
return false;
}
//make 2 dimension to 1 dimension
public Integer convert(int x,int y,int col){
return x*col+y;
}
}
``
Clone Graph
Description
Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors. Nodes are labeled uniquely.
You need to return a deep copied graph, which has the same structure as the original graph, and any changes to the new graph will not have any effect on the original graph.
You need return the node with the same label as the input node.
How we represent an undirected graph: http://www.lintcode.com/help/graph/
Example
Example1
Input:
{1,2,4#2,1,4#4,1,2}
Output:
{1,2,4#2,1,4#4,1,2}
Explanation:
1------2
\ |
\ |
\ |
\ |
4
Nodes are separated by '#'
1,2,4indicates a node label = 1, neighbors = [2,4]
2,1,4 indicates a node label = 2, neighbors = [1,4]
4,1,2 indicates a node label = 4, neighbors = [1,2]
``
/**
* Definition for Undirected graph.
* class UndirectedGraphNode {
* int label;
* List<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) {
// write your code here
if(node == null){
return null;
}
//find all nodes
List<UndirectedGraphNode> allOldNodes = findAllNodesByBFS(node);
//copy all nodes
HashMap<UndirectedGraphNode,UndirectedGraphNode> oldToNewMapping = copyAllNodes(allOldNodes);
//copy all edge
copyAllEdges(allOldNodes,oldToNewMapping);
return oldToNewMapping.get(node);
}
public void copyAllEdges(List<UndirectedGraphNode> allOldNodes,HashMap<UndirectedGraphNode,UndirectedGraphNode> mapping){
for(UndirectedGraphNode oldNode : allOldNodes){
UndirectedGraphNode newNode = mapping.get(oldNode);
System.out.println("newNode.label"+newNode.label);
for(UndirectedGraphNode neighbors : oldNode.neighbors){
// System.out.println("neighbors"+neighbors.label);
UndirectedGraphNode newNeighbor = mapping.get(neighbors);
newNode.neighbors.add(newNeighbor);
}
}
}
public HashMap<UndirectedGraphNode,UndirectedGraphNode> copyAllNodes( List<UndirectedGraphNode> allOldNodes){
HashMap<UndirectedGraphNode,UndirectedGraphNode> mapping = new HashMap<>();
for(UndirectedGraphNode oldNode :allOldNodes){
// System.out.println("newNode"+new UndirectedGraphNode(oldNode.label).label);
mapping.put(oldNode,new UndirectedGraphNode(oldNode.label));
}
return mapping;
}
public List<UndirectedGraphNode> findAllNodesByBFS(UndirectedGraphNode node){
ArrayList<UndirectedGraphNode> visited = new ArrayList<>();
Queue<UndirectedGraphNode> queue = new ArrayDeque<UndirectedGraphNode>();
queue.offer(node);
visited.add(node);
while(!queue.isEmpty()){
UndirectedGraphNode currentNode = queue.poll();
for(UndirectedGraphNode neighbors : currentNode.neighbors){
if(visited.contains(neighbors)){
continue;
}
visited.add(neighbors);
queue.offer(neighbors);
}
}
// Pass hashset to arraylist constructor
for(int i =0;i<visited.size();i++){
System.out.println(visited.get(i).label);
}
return visited;
}
}
``
Topological Sorting
有向图的一种遍历的顺序 从a->b 那么先输出a再输出b a的入度为0 b的入度为1 。由此可以看出是从小的入度到大的入度去遍历。
- 1.统计所有的点的入度
- 将每个入度为0 的点放入到queue中作为下一层次要遍历的点
- 不断的遍历queue中的每一个点,去掉这个点指向的邻居的边,也就是邻居的入度减去1.
- 如果邻居的点符合要求:“入度为0”那么加入到队列中。作为下一个要sorting的点。
所以进入到队列的顺序也就是点的入度不断为0的点,也就是toplogical sorting的顺序
Description
Given an directed graph, a topological order of the graph nodes is defined as follow:
For each directed edge A -> B in graph, A must before B in the order list.
The first node in the order can be any node in the graph with no nodes direct to it.
Find any topological order for the given graph.
Contact me on wechat to get Amazon、Google requent Interview questions . (wechat id : jiuzhang0607)
You can assume that there is at least one topological order in the graph.
Learn more about representation of graphs
The number of graph nodes <= 5000
Example
Example 1:
Input:
graph = {0,1,2,3#1,4#2,4,5#3,4,5#4#5}
Output:
[0, 1, 2, 3, 4, 5]
Explanation:
For graph as follow:
图片
he topological order can be:
[0, 1, 2, 3, 4, 5]
[0, 2, 3, 1, 5, 4]
...
You only need to return any topological order for the given graph.
Challenge
Can you do it in both BFS and DFS?
``
/**
* Definition for Directed graph.
* class DirectedGraphNode {
* int label;
* List<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) {
// write your code here
//corner case
if(graph == null){
return null;
}
// 1.count all degree of the graph
HashMap<DirectedGraphNode,Integer> indegree = getIndegree(graph);
// 2.put every indegree = 0 node into queue
Queue<DirectedGraphNode> queue = new ArrayDeque<DirectedGraphNode>();
for(DirectedGraphNode node : graph){
if (!indegree.containsKey(node)){
queue.offer(node);
}
}
//3. get the order of topological graph
ArrayList order = new ArrayList<DirectedGraphNode>();
while(!queue.isEmpty()){
DirectedGraphNode node = queue.poll();
order.add(node);
for(DirectedGraphNode neighbors:node.neighbors){
indegree.put(neighbors,indegree.get(neighbors)-1);
if(indegree.get(neighbors) == 0){
queue.offer(neighbors);
}
}
}
return order;
}
public HashMap<DirectedGraphNode,Integer> getIndegree(ArrayList<DirectedGraphNode> graph){
HashMap<DirectedGraphNode,Integer> indegree = new HashMap<DirectedGraphNode,Integer>();
for(DirectedGraphNode node : graph){
for(DirectedGraphNode neighbors : node.neighbors ){
indegree.put(neighbors,indegree.getOrDefault(neighbors,0)+1);
}
}
return indegree;
}
}
``
Word Ladder
这个题属于图的层级遍历的问题 level order traversal
- 主要是转移的列表
- 构建这个图“树”的一种构建过程
- 至到生成到end词典为止
- 返回的是“第几层”
Description
Given two words (start and end), and a dictionary, find the shortest transformation sequence from start to end, output the length of the sequence.
Transformation rule such that:
Only one letter can be changed at a time
Each intermediate word must exist in the dictionary. (Start and end words do not need to appear in the dictionary ))
Contact me on wechat to get Amazon、Google requent Interview questions . (wechat id : jiuzhang0607)
Return 0 if there is no such transformation sequence.
All words have the same length.
All words contain only lowercase alphabetic characters.
You may assume no duplicates in the dictionary.
You may assume beginWord and endWord are non-empty and are not the same.
len(dict) <= 5000, len(start) < 5len(dict)<=5000,len(start)<5
Example
Example 1:
Input:
start = "a"
end = "c"
dict =["a","b","c"]
Output:
2
Explanation:
"a"->"c"
Example 2:
Input:
start ="hit"
end = "cog"
dict =["hot","dot","dog","lot","log"]
Output:
5
Explanation:
"hit"->"hot"->"dot"->"dog"->"cog"
``
public class Solution {
/**
* @param start: a string
* @param end: a string
* @param dict: a set of string
* @return: An integer
*/
public int ladderLength(String start, String end, Set<String> dict) {
// write your code here
if(dict == null){
return 0;
}
dict.add(end);
Set<String> visited = new HashSet<String>();
Queue<String> queue = new ArrayDeque<String>();
queue.offer(start);
visited.add(start);
int length = 1;
while(!queue.isEmpty()){
length=length+1;
int size =queue.size();
for(int i =0;i < size;i++){
String word = queue.poll();
System.out.println("word|length:"+word+"->"+length);
for(String nextWord : getNext(word,dict)){
if(nextWord.equals(end)){
return length;
}
if(visited.contains(nextWord)){
continue;
}
queue.offer(nextWord);
visited.add(nextWord);
}
}
}
return 0;
}
public ArrayList<String> getNext(String word,Set<String> dict){
// dict
System.out.println("word:"+word);
ArrayList<String> nextWordList = new ArrayList<String>();
for(String everyWord:dict){
// System.out.println("everyWord:"+everyWord);
boolean hasOneDiff = false;
for(int i = 0; i < everyWord.length(); i++){
if(everyWord.charAt(i) != word.charAt(i)){
if(hasOneDiff == true){
hasOneDiff = false;
break;
}
hasOneDiff = true;
}
}
if(hasOneDiff == true){t
// System.out.println("add into next:"+everyWord);
nextWordList.add(everyWord);
}
}
System.out.println("nextWordList"+nextWordList.toString());
return nextWordList;
}
}
``