视频教程:B站、网易云课堂、腾讯课堂
代码地址:Gitee、Github
存储地址:
百度云-提取码:
Google云
- 1.二叉树的层序遍历
- 2.最小基因变化
- 3.括号生成
- 4.在每个树行中找最大值
- 5.单词接龙
- 6.单词接龙 II
- 7.岛屿数量
- 8.扫雷游戏
补充:递归并不意味着效率差,主要可能是因为没有用缓存,等等原因
树节点:
python版:
class TreeNode:
def __init__(self,val):
self.val = val
self.left,self.right = None,None
C++版:
struct TreeNode{
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x):val(x),left(NULL),right(NULL){}
}
Java版:
public class TreeNode {
public int val;
public TreeNode left,right;
public TreeNode(int val){
this.val = val;
this.left = null;
this.right = null;
}
}
Python版不同的遍历:
def preorder(self,root):
if root:
self.traverse_path.append(root.val)
self.preorder(root.left)
self.preorder(root.right)
def inorder(self,root):
if root:
self.preorder(root.left)
self.traverse_path.append(root.val)
self.preorder(root.right)
def postorder(self,root):
if root:
self.preorder(root.left)
self.preorder(root.right)
self.traverse_path.append(root.val)
常见操作:查询、插入、删除
树的面试题或者大部分问题,用的都是递归,主要是因为树的结构是由左右子节点构成的原因,使用递归会更加简单便捷
- 二叉树的层序遍历
国内站
java版
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
python版:
'''
思路:
'''
'''
评价:
优点:
缺点:
'''
c++版:
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
国外站
java版
/*
思路:
*/
public class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<TreeNode>();
List<List<Integer>> wrapList = new LinkedList<List<Integer>>();
if(root == null) return wrapList;
queue.offer(root);
while(!queue.isEmpty()){
int levelNum = queue.size();
List<Integer> subList = new LinkedList<Integer>();
for(int i=0; i<levelNum; i++) {
if(queue.peek().left != null) queue.offer(queue.peek().left);
if(queue.peek().right != null) queue.offer(queue.peek().right);
subList.add(queue.poll().val);
}
wrapList.add(subList);
}
return wrapList;
}
}
/*
评价:
优点:
缺点:
*/
python版:
'''
思路:
'''
class Solution(object):
def levelOrder(self, root):
res = []
self.dfs(root, 0, res)
return res
def dfs(self, root, level, res):
if not root:
return
if len(res) < level+1:
res.append([])
res[level].append(root.val)
self.dfs(root.left, level+1, res)
self.dfs(root.right, level+1, res)
'''
评价:
优点:
缺点:
'''
c++版:
/*
思路:
*/
class Solution {
public:
vector<vector<int> > levelOrder(TreeNode *root) {
vector<vector<int> > result;
if (!root) return result;
queue<TreeNode*> q;
q.push(root);
q.push(NULL);
vector<int> cur_vec;
while(!q.empty()) {
TreeNode* t = q.front();
q.pop();
if (t==NULL) {
result.push_back(cur_vec);
cur_vec.resize(0);
if (q.size() > 0) {
q.push(NULL);
}
} else {
cur_vec.push_back(t->val);
if (t->left) q.push(t->left);
if (t->right) q.push(t->right);
}
}
return result;
}
};
/*
评价:
优点:
缺点:
*/
- 最小基因变化
国内站
java版
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
python版:
'''
思路:
'''
'''
评价:
优点:
缺点:
'''
c++版:
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
国外站
java版
/*
思路:
*/
public class Solution {
public int minMutation(String start, String end, String[] bank) {
if(start.equals(end)) return 0;
Set<String> bankSet = new HashSet<>();
for(String b: bank) bankSet.add(b);
char[] charSet = new char[]{'A', 'C', 'G', 'T'};
int level = 0;
Set<String> visited = new HashSet<>();
Queue<String> queue = new LinkedList<>();
queue.offer(start);
visited.add(start);
while(!queue.isEmpty()) {
int size = queue.size();
while(size-- > 0) {
String curr = queue.poll();
if(curr.equals(end)) return level;
char[] currArray = curr.toCharArray();
for(int i = 0; i < currArray.length; i++) {
char old = currArray[i];
for(char c: charSet) {
currArray[i] = c;
String next = new String(currArray);
if(!visited.contains(next) && bankSet.contains(next)) {
visited.add(next);
queue.offer(next);
}
}
currArray[i] = old;
}
}
level++;
}
return -1;
}
}
/*
评价:
优点:
缺点:
*/
python版:
'''
思路:
'''
'''
评价:
优点:
缺点:
'''
c++版:
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
- 括号生成
国内站
java版
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
python版:
'''
思路:
'''
'''
评价:
优点:
缺点:
'''
c++版:
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
国外站
java版
/*
思路:
*/
class Solution {
public List<String> generateParenthesis(int n) {
List<String> list = new ArrayList<String>();
backtrack(list,"",0,0,n);
return list;
}
public void backtrack(List<String> list,String str,int open,int close,int max) {
if (str.length() == max*2 ) {
list.add(str);
return;
}
if (open <max )
backtrack(list,str+"(",open+1,close,max);
if (close <open )
backtrack(list,str+")",open,close+1,max);
}
}
/*
评价:
优点:
缺点:
*/
python版:
'''
思路:
'''
'''
评价:
优点:
缺点:
'''
c++版:
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
- 在每个树行中找最大值
国内站
java版
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
python版:
'''
思路:
'''
'''
评价:
优点:
缺点:
'''
c++版:
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
国外站
java版
/*
思路:
*/
public class Solution {
public List<Integer> largestValues(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
helper(root, res, 0);
return res;
}
private void helper(TreeNode root, List<Integer> res, int d){
if(root == null){
return;
}
//expand list size
if(d == res.size()){
res.add(root.val);
}
else{
//or set value
res.set(d, Math.max(res.get(d), root.val));
}
helper(root.left, res, d+1);
helper(root.right, res, d+1);
}
}
/*
评价:
优点:
缺点:
*/
python版:
'''
思路:
'''
'''
评价:
优点:
缺点:
'''
c++版:
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
- 单词接龙
国内站
java版
/*
思路:
*/
class Solution {
public int ladderLength(String beginWord, String endWord, List<String> wordList) {
// Since all words are of same length.
int L = beginWord.length();
// Dictionary to hold combination of words that can be formed,
// from any given word. By changing one letter at a time.
Map<String, List<String>> allComboDict = new HashMap<>();
wordList.forEach(
word -> {
for (int i = 0; i < L; i++) {
// Key is the generic word
// Value is a list of words which have the same intermediate generic word.
String newWord = word.substring(0, i) + '*' + word.substring(i + 1, L);
List<String> transformations = allComboDict.getOrDefault(newWord, new ArrayList<>());
transformations.add(word);
allComboDict.put(newWord, transformations);
}
});
// Queue for BFS
Queue<Pair<String, Integer>> Q = new LinkedList<>();
Q.add(new Pair(beginWord, 1));
// Visited to make sure we don't repeat processing same word.
Map<String, Boolean> visited = new HashMap<>();
visited.put(beginWord, true);
while (!Q.isEmpty()) {
Pair<String, Integer> node = Q.remove();
String word = node.getKey();
int level = node.getValue();
for (int i = 0; i < L; i++) {
// Intermediate words for current word
String newWord = word.substring(0, i) + '*' + word.substring(i + 1, L);
// Next states are all the words which share the same intermediate state.
for (String adjacentWord : allComboDict.getOrDefault(newWord, new ArrayList<>())) {
// If at any point if we find what we are looking for
// i.e. the end word - we can return with the answer.
if (adjacentWord.equals(endWord)) {
return level + 1;
}
// Otherwise, add it to the BFS Queue. Also mark it visited
if (!visited.containsKey(adjacentWord)) {
visited.put(adjacentWord, true);
Q.add(new Pair(adjacentWord, level + 1));
}
}
}
}
return 0;
}
}
/*
评价:
优点:
缺点:
*/
python版:
'''
思路:
'''
'''
评价:
优点:
缺点:
'''
c++版:
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
国外站
java版
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
python版:
'''
思路:
'''
'''
评价:
优点:
缺点:
'''
c++版:
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
- 单词接龙 II
国内站
java版
/*
思路:
*/
class Solution {
private static final int INF = 1 << 20;
private Map<String, Integer> wordId; // 单词到id的映射
private ArrayList<String> idWord; // id到单词的映射
private ArrayList<Integer>[] edges; // 图的边
public Solution() {
wordId = new HashMap<>();
idWord = new ArrayList<>();
}
public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
int id = 0;
// 将wordList所有单词加入wordId中 相同的只保留一个 // 并为每一个单词分配一个id
for (String word : wordList) {
if (!wordId.containsKey(word)) {
wordId.put(word, id++);
idWord.add(word);
}
}
// 若endWord不在wordList中 则无解
if (!wordId.containsKey(endWord)) {
return new ArrayList<>();
}
// 把beginWord也加入wordId中
if (!wordId.containsKey(beginWord)) {
wordId.put(beginWord, id++);
idWord.add(beginWord);
}
// 初始化存边用的数组
edges = new ArrayList[idWord.size()];
for (int i = 0; i < idWord.size(); i++) {
edges[i] = new ArrayList<>();
}
// 添加边
for (int i = 0; i < idWord.size(); i++) {
for (int j = i + 1; j < idWord.size(); j++) {
// 若两者可以通过转换得到 则在它们间建一条无向边
if (transformCheck(idWord.get(i), idWord.get(j))) {
edges[i].add(j);
edges[j].add(i);
}
}
}
int dest = wordId.get(endWord); // 目的ID
List<List<String>> res = new ArrayList<>(); // 存答案
int[] cost = new int[id]; // 到每个点的代价
for (int i = 0; i < id; i++) {
cost[i] = INF; // 每个点的代价初始化为无穷大
}
// 将起点加入队列 并将其cost设为0
Queue<ArrayList<Integer>> q = new LinkedList<>();
ArrayList<Integer> tmpBegin = new ArrayList<>();
tmpBegin.add(wordId.get(beginWord));
q.add(tmpBegin);
cost[wordId.get(beginWord)] = 0;
// 开始广度优先搜索
while (!q.isEmpty()) {
ArrayList<Integer> now = q.poll();
int last = now.get(now.size() - 1); // 最近访问的点
if (last == dest) { // 若该点为终点则将其存入答案res中
ArrayList<String> tmp = new ArrayList<>();
for (int index : now) {
tmp.add(idWord.get(index)); // 转换为对应的word
}
res.add(tmp);
} else { // 该点不为终点 继续搜索
for (int i = 0; i < edges[last].size(); i++) {
int to = edges[last].get(i);
// 此处<=目的在于把代价相同的不同路径全部保留下来
if (cost[last] + 1 <= cost[to]) {
cost[to] = cost[last] + 1;
// 把to加入路径中
ArrayList<Integer> tmp = new ArrayList<>(now); tmp.add(to);
q.add(tmp); // 把这个路径加入队列
}
}
}
}
return res;
}
// 两个字符串是否可以通过改变一个字母后相等
boolean transformCheck(String str1, String str2) {
int differences = 0;
for (int i = 0; i < str1.length() && differences < 2; i++) {
if (str1.charAt(i) != str2.charAt(i)) {
++differences;
}
}
return differences == 1;
}
}
/*
评价:
优点:
缺点:
*/
python版:
'''
思路:
'''
'''
评价:
优点:
缺点:
'''
c++版:
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
国外站
java版
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
python版:
'''
思路:
'''
'''
评价:
优点:
缺点:
'''
c++版:
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
- 岛屿数量
国内站
java版
/*
思路:
*/
class Solution {
void dfs(char[][] grid, int r, int c) {
int nr = grid.length;
int nc = grid[0].length;
if (r < 0 || c < 0 || r >= nr || c >= nc || grid[r][c] == '0') {
return;
}
grid[r][c] = '0';
dfs(grid, r - 1, c);
dfs(grid, r + 1, c);
dfs(grid, r, c - 1);
dfs(grid, r, c + 1);
}
public int numIslands(char[][] grid) {
if (grid == null || grid.length == 0) {
return 0;
}
int nr = grid.length;
int nc = grid[0].length;
int num_islands = 0;
for (int r = 0; r < nr; ++r) {
for (int c = 0; c < nc; ++c) {
if (grid[r][c] == '1') {
++num_islands;
dfs(grid, r, c);
}
}
}
return num_islands;
}
}
/*
评价:
优点:
缺点:
*/
python版:
'''
思路:
'''
'''
评价:
优点:
缺点:
'''
c++版:
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
国外站
java版
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
python版:
'''
思路:
'''
'''
评价:
优点:
缺点:
'''
c++版:
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
- 扫雷游戏
国内站
java版
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
python版:
'''
思路:
'''
'''
评价:
优点:
缺点:
'''
c++版:
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
国外站
java版
/*
思路:
*/
public class Solution {
public char[][] updateBoard(char[][] board, int[] click) {
int m = board.length, n = board[0].length;
int row = click[0], col = click[1];
if (board[row][col] == 'M') { // Mine
board[row][col] = 'X';
}
else { // Empty
// Get number of mines first.
int count = 0;
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
if (i == 0 && j == 0) continue;
int r = row + i, c = col + j;
if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) continue;
if (board[r][c] == 'M' || board[r][c] == 'X') count++;
}
}
if (count > 0) { // If it is not a 'B', stop further DFS.
board[row][col] = (char)(count + '0');
}
else { // Continue DFS to adjacent cells.
board[row][col] = 'B';
for (int i = -1; i < 2; i++) {
for (int j = -1; j < 2; j++) {
if (i == 0 && j == 0) continue;
int r = row + i, c = col + j;
if (r < 0 || r >= m || c < 0 || c < 0 || c >= n) continue;
if (board[r][c] == 'E') updateBoard(board, new int[] {r, c});
}
}
}
}
return board;
}
}
/*
评价:
优点:
缺点:
*/
python版:
'''
思路:
'''
'''
评价:
优点:
缺点:
'''
c++版:
/*
思路:
*/
/*
评价:
优点:
缺点:
*/
一 深度优先搜索、广度优先搜索的实现和特性
二 实战题目解析:二叉树的层次遍历等问题