DFS leetcode
把字符串转换成整数
class Solution {
public:
int StrToInt(string str) {
int n = str.size(), s = 1;
long long res = 0;
if(!n) return 0;
if(str[0] == '-') s = -1;
for(int i = (str[0] == '-' || str[0] == '+') ? 1 : 0; i < n; ++i){
if(!('0' <= str[i] && str[i] <= '9')) return 0;
res = (res << 1) + (res << 3) + (str[i] & 0xf);//res=res*10+str[i]-'0';
}
return res * s;
}
};
res = (res << 1) + (res << 3) + (str[i] & 0xf);
和res=res*10+str[i]-'0'是一样的。左移是乘以2的次方。(res << 1) + (res << 3) = res * 2 + res * 8 = res * 10 。
str[i] & 0xf:针对字符0-9的,0-9的ascii码值为0x30,0x31,0x32 0x33 ...0x39,因此与0x0f按位与后只保留个位上的书即0x0,0x1,。。。0x9
113. Path Sum II
只要在root为null返回就行了,不该return那么多地方。
public List<List<Integer>> pathSum(TreeNode root, int sum) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> list = new ArrayList<>();
helper(res, list, root, sum);
return res;
}
private void helper(List<List<Integer>> res, List<Integer> list, TreeNode root, int sum) {
if (root == null) return;
list.add(root.val);
if (root.left == null && root.right == null && root.val == sum) {
res.add(new ArrayList<>(list));
}
helper(res, list, root.left, sum - root.val);
helper(res, list, root.right, sum - root.val);
list.remove(list.size() - 1);
}
res.add(new ArrayList<>(list));
必须new,不然随着list的remove操作res的list内容也会被删除
最后逐级remove掉list最后一个节点,其他路径不会加上当前路径的节点
java List复制:浅拷贝与深拷贝
list.remove(list.size() - 1);
删除列表最后一个元素
114. Flatten Binary Tree to Linked List
把树压缩成链表,用root.right连接后面的结点
private TreeNode prev = null;
public void flatten(TreeNode root) {
if (root == null)
return;
flatten(root.right);
flatten(root.left);
root.right = prev;
root.left = null;
prev = root;
}
原始树:链表形式:
算法访问顺序是右,左,中,prev存前一个访问的结点,按访问顺序后一个的right=前一个。如图,顺序是6->5->4->3->2->1,所以5的right是6,以此类推 从后往前连接。
129. Sum Root to Leaf Numbers
根节点到每个叶节点都可以从根到叶排成一个数,求这些数的和
public int sumNumbers(TreeNode root) {
return sum(root, 0);
} public int sum(TreeNode n, int s){
if (n == null) return 0;
if (n.right == null && n.left == null) return s*10 + n.val;
return sum(n.left, s*10 + n.val) + sum(n.right, s*10 + n.val);
}
我想的是递归时修改s的值再还原,其实完全没必要修改,传递时用s*10 + n.val
199. Binary Tree Right Side View
列出从树的右侧能看到的节点
树从右至左的遍历,中->右->左
public class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> result = new ArrayList<Integer>();
rightView(root, result, 0);
return result;
} public void rightView(TreeNode curr, List<Integer> result, int currDepth){
if(curr == null){
return;
}
if(currDepth == result.size()){
result.add(curr.val);
} rightView(curr.right, result, currDepth + 1);
rightView(curr.left, result, currDepth + 1); }
}
332. Reconstruct Itinerary
public List<String> findItinerary(String[][] tickets) {
Map<String, PriorityQueue<String>> targets = new HashMap<>();
for (String[] ticket : tickets)
targets.computeIfAbsent(ticket[0], k -> new PriorityQueue()).add(ticket[1]);
List<String> route = new LinkedList();
Stack<String> stack = new Stack<>();
stack.push("JFK");
while (!stack.empty()) {
while (targets.containsKey(stack.peek()) && !targets.get(stack.peek()).isEmpty())
stack.push(targets.get(stack.peek()).poll());
//peek() 方法用于查找在此堆栈顶部的对象,无需从堆栈中取出。
//poll() 和 remove() 都是从队列中取出一个元素,但是 poll() 在获取元素失败的时候会返回空,但是 remove() 失败的时候会抛出异常。
route.add(0, stack.pop());//插入到链表头
}
return route;
}
computeIfAbsent: 如果map里没有这个key,那么就按照后面的这个function添加对应的key和value
如果要这个key,那么就不添加
看了别人的思路,基本是bottom up的DFS,就是路径是反向从最低层往上得出的.
将所有的机票用hash表保存起来,最后我们就是要找出一条路径将机票用完,并且如果有多条路径,就找字典序最小的.
我们可以构造一个hash表,key为一个地点字符串,value为一个PriorityQueue保存这个地点可以飞到的其他地方,之所以用PriorityQueue是因为从一个地方可以去别的地方几次.并且这个数据结构是可以将数据排序的,方便我们有序的取数据.
然后我们利用DFS思想从"JFK"机场出发,按照字典序从小到达取与其连接的地点,从下一个地点再递归的搜索,直到没有和某地点相连的机票的了.我们就到达了最底层,然后往上返回路径即可.
6ms:
class Solution { HashMap<String,PriorityQueue<String>> ticketsMap=new HashMap<>();
LinkedList<String> result=new LinkedList<>(); public List<String> findItinerary(String[][] tickets) {
if(tickets==null) return result; //构造hashmap
for(String[] ticket:tickets){
if(!ticketsMap.containsKey(ticket[0])) ticketsMap.put(ticket[0],new PriorityQueue<>());
ticketsMap.get(ticket[0]).offer(ticket[1]);
} DFS("JFK");
return result;
} public void DFS(String ticket){
PriorityQueue<String> temp=ticketsMap.get(ticket);
while (temp!=null && !temp.isEmpty()){
DFS(temp.poll());
}
result.addFirst(ticket);
}
}
101. Symmetric Tree
判断一颗树是不是沿中线左右对称
对称 不对称
非递归:也可以用两个队列分别存两边的。
public boolean isSymmetric(TreeNode root) {
Queue<TreeNode> q = new LinkedList<TreeNode>();
if(root == null) return true;
q.add(root.left);
q.add(root.right);
while(q.size() > 1){
TreeNode left = q.poll(),
right = q.poll();
//如果都是空就继续
if(left== null&& right == null) continue;
//不全为空就返回false
if(left == null ^ right == null) return false;
if(left.val != right.val) return false;
q.add(left.left);//可能有空
q.add(right.right);//从树的外围向里面成对push
q.add(left.right);
q.add(right.left);
}
return true;
}
递归:短路法
public boolean isSymmetric(TreeNode root) {
if(root==null) return true;
return isMirror(root.left,root.right);
}
public boolean isMirror(TreeNode p, TreeNode q) {
if(p==null && q==null) return true;
if(p==null || q==null) return false;
return (p.val==q.val) && isMirror(p.left,q.right) && isMirror(p.right,q.left);
}
1、在方法体内对参数进行运算,不会影响原有变量的值(基本类型不会改变值,引用类型不会改变引用地址)。
public class ParamTest { public static void integerParam(int a,int b){
a += 1;
b += 1;
} public static void quoteParam(Random x){
x = new Random();
} public static void main(String[] args) {
int a = 1;
int b = 2;
integerParam(1,2);
System.out.println("a:"+a);
System.out.println("b:"+b); System.out.println("=======我是分割线======"); Random r = new Random();
System.out.println(r);
quoteParam(r);
System.out.println(r);
}
}
输出结果:a:1
b:2
=======我是分割线======
java.util.Random@5910e440
java.util.Random@5910e440
说明整数类型在方法体内没有改变值,引用类型的地址也没发生变化。
2、在方法体内对参数的属性进行操作,将改变原有变量的属性值(如集合、数组中的元素)
public class ParamTest { public static void integerParam(int a,int b){
a += 1;
b += 1;
} public static void quoteParam(Random x){
x = new Random();
} public static void arrayParam(String[] strArray){
strArray[0] = "a";
strArray[1] = "b"; } public static void main(String[] args) {
int a = 1;
int b = 2;
integerParam(1,2);
System.out.println("a:"+a);
System.out.println("b:"+b); System.out.println("=======我是分割线======"); Random r = new Random();
System.out.println(r);
quoteParam(r);
System.out.println(r); System.out.println("========我是分割线========="); String[] strArray = new String[2];
strArray[0] = "x";
System.out.println(strArray);
for (int i = 0; i < strArray.length; i++) {
System.out.println(strArray[i]);
}
arrayParam(strArray);
System.out.println(strArray);
for (int i = 0; i < strArray.length; i++) {
System.out.println(strArray[i]);
}
}
输出结果:
a:1
b:2
=======我是分割线======
java.util.Random@5910e440
java.util.Random@5910e440
========我是分割线=========
[Ljava.lang.String;@6267c3bb
x
null
[Ljava.lang.String;@6267c3bb
a
b
我们可以看到在最下边数组参数的测试结果中,参数的引用地址没有发生变化,而参数内部的元素发生了变化。
417. Pacific Atlantic Water Flow
这道题给了我们一个二维数组,说是数组的左边和上边是太平洋,右边和下边是大西洋,假设水能从高处向低处流,问我们所有能流向两大洋的点的集合。刚开始我们没有理解题意,以为加括号的点是一条路径,连通两大洋的,但是看来看去感觉也不太对,后来终于明白了,是每一个点单独都路径来通向两大洋。那么就是典型的搜索问题,那么我最开始想的是对于每个点来搜索是否能到达边缘,只不过搜索的目标点不在是一个单点,而是所有的边缘点,找这种思路写出的代码无法通过OJ大数据集,那么我们就要想办法来优化我们的代码,优化的方法跟之前那道Surrounded Regions很类似,都是换一个方向考虑问题,既然从每个点像中间扩散会TLE,那么我们从边缘当作起点开始遍历搜索,然后标记能到达的点位true,分别标记出pacific和atlantic能到达的点,那么最终能返回的点就是二者均为true的点。我们可以先用DFS来遍历二维数组,参见代码如下:
public class Solution {
public List<int[]> pacificAtlantic(int[][] matrix) {
List<int[]> res = new LinkedList<>();
if(matrix == null || matrix.length == 0 || matrix[0].length == 0){
return res;
}
int n = matrix.length, m = matrix[0].length;
boolean[][]pacific = new boolean[n][m];
boolean[][]atlantic = new boolean[n][m];
for(int i=0; i<n; i++){
dfs(matrix, pacific, Integer.MIN_VALUE, i, 0);
dfs(matrix, atlantic, Integer.MIN_VALUE, i, m-1);
}
for(int i=0; i<m; i++){
dfs(matrix, pacific, Integer.MIN_VALUE, 0, i);
dfs(matrix, atlantic, Integer.MIN_VALUE, n-1, i);
}
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (pacific[i][j] && atlantic[i][j])
res.add(new int[] {i, j});
return res;
} int[][]dir = new int[][]{{0,1},{0,-1},{1,0},{-1,0}}; public void dfs(int[][]matrix, boolean[][]visited, int height, int x, int y){
int n = matrix.length, m = matrix[0].length;
if(x<0 || x>=n || y<0 || y>=m || visited[x][y] || matrix[x][y] < height)
return;
visited[x][y] = true;
for(int[]d:dir){
dfs(matrix, visited, matrix[x][y], x+d[0], y+d[1]);
}
}
}
472. Concatenated Words
题解: 从list中找出所有字符串,该字符串至少由list中的两个单词构成。
我们首先按字符串长度由小到大排列words. 然后构造一个set, 依次加入set中。对于具体的字符串word,如果word可以由至少set中的两个word构成,则该word加入结果集中。这种字符串的prefix问题,很明显要用dynamic programming来解。
public class Solution {
public static List<String> findAllConcatenatedWordsInADict(String[] words) {
List<String> result = new ArrayList<>();
Set<String> preWords = new HashSet<>();
Arrays.sort(words, new Comparator<String>() {
public int compare (String s1, String s2) {
return s1.length() - s2.length();
}
}); for (int i = 0; i < words.length; i++) {
if (canForm(words[i], preWords)) {
result.add(words[i]);
}
preWords.add(words[i]);
} return result;
} private static boolean canForm(String word, Set<String> dict) {
if (dict.isEmpty()) return false;
boolean[] dp = new boolean[word.length() + 1];
dp[0] = true;
for (int i = 1; i <= word.length(); i++) {
for (int j = 0; j < i; j++) {
if (!dp[j]) continue;
if (dict.contains(word.substring(j, i))) {
dp[i] = true;
break;
}
}
}
return dp[word.length()];
}
}
也可以用trie树保存list结合dfs
491. Increasing Subsequences
找到全部连续增长的序列,数字可能会重复,输入数组并不是一直增长的,可能会比前面小,所以不能排序
Input: [4, 6, 7, 7]
Output: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]
public List<List<Integer>> findSubsequences(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
SubList(nums, list, new ArrayList<>(), );
for (int i = ; i < list.size(); i++) {
System.out.println(list.get(i));
} return list;
} public void SubList(int[] nums, List<List<Integer>> list, List<Integer> temp, int pos) {
if (pos >= nums.length) {
return;
}
//保存访问过的数字,如果已经访问过一次就跳过,避免同一个位置访问多次同一个数字,这样结果就不会出现重复地序列
Set<Integer> used = new HashSet<>(); for (int i = pos; i < nums.length; i++) { if (used.contains(nums[i]) || (temp.size() > && temp.get(temp.size() - ) > nums[i])) {
continue;
}
used.add(nums[i]);
temp.add(nums[i]);
if (temp.size() >= ) {
list.add(new ArrayList<>(temp));
} SubList(nums, list, temp, i + );
temp.remove(temp.size() - );
} }
542. 01 Matrix
LeetCode Weekly Contest 24 之 542.01 Matrix
给定一个只含0和1的矩阵,找到每个1到0的最短距离。
两个相邻单元格的距离是1
普通dfs会超时,最短距离用bfs
本题目中其实质就是求出每个单元格到其最近0之间的最短路径,可以使用广度优先(BFS)搜索进行求解。广度优先搜索一般使用队列实现。
首先将矩阵中matrix中元素值为零的单元格的坐标入队q中,其最短距离矩阵ans中相应值设置为0,将元素值为1的单元格的最短距离ans设置为-1;
从队首q中取出元素front,将其相邻且未被访问过的单元格的最短距离ans设为ans[front]+1,并入队。
public class Solution {
public int[][] updateMatrix(int[][] matrix) {
int m = matrix.length;
int n = matrix[0].length; Queue<int[]> queue = new LinkedList<>();
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == 0) {
queue.offer(new int[] {i, j});//把0元素加入队列中,以备波及影响周围元素
}
else {
matrix[i][j] = Integer.MAX_VALUE;//设为最大值,方便求0元素影响值
}
}
}
//代表传播的四个方向
int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; while (!queue.isEmpty()) {
int[] cell = queue.poll();
for (int[] d : dirs) {
//需要比较的下一位置元素
int r = cell[0] + d[0];
int c = cell[1] + d[1];
//不符合条件的均跳过,找来的比如:0 的周围 还是0的哪些元素,1的周围是1,但不符合影响值更新规则的同样忽略。
if (r < 0 || r >= m || c < 0 || c >= n ||
matrix[r][c] <= matrix[cell[0]][cell[1]] + 1) continue;
//把受0波及的1元素也放入队列中,涟漪是会持续的。
queue.add(new int[] {r, c});
matrix[r][c] = matrix[cell[0]][cell[1]] + 1;
}
} return matrix;
}
}
java.util.ArrayList.set(int index, E element) 替换与指定元素在此列表中指定位置的元素。
list.set(0,1)
java Queue中 remove/poll, add/offer, element/peek区别:是否抛出异常
offer,add区别:
一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,多出的项就会被拒绝。
这时新的 offer 方法就可以起作用了。它不是对调用 add() 方法抛出一个 unchecked 异常,而只是得到由 offer() 返回的 false。
poll,remove区别:
remove() 和 poll() 方法都是从队列中删除第一个元素。remove() 的行为与 Collection 接口的版本相似,
但是新的 poll() 方法在用空集合调用时不是抛出异常,只是返回 null。因此新的方法更适合容易出现异常条件的情况。
peek,element区别:
element() 和 peek() 用于在队列的头部查询元素。与 remove() 方法类似,在队列为空时, element() 抛出一个异常,而 peek() 返回 null
79. Word Search
这道题是典型的深度优先遍历 DFS 的应用,原二维数组就像是一个迷宫,可以上下左右四个方向行走,我们以二维数组中每一个数都作为起点和给定字符串做匹配,因为题目要求一个 cell 只能被访问一次,所以访问后的位置就异或256,这样就不会与ascii的任何字母重合,之后在还原。如果二维数组 board 的当前字符和目标字符串 word 对应的字符相等,则对其上下左右四个邻字符分别调用 DFS 的递归函数,只要有一个返回 true,那么就表示可以找到对应的字符串,否则就不能找到
public boolean exist(char[][] board, String word) {
char[] w = word.toCharArray();
for (int y=0; y<board.length; y++) {
for (int x=0; x<board[y].length; x++) {
if (exist(board, y, x, w, 0)) return true;
}
}
return false;
} private boolean exist(char[][] board, int y, int x, char[] word, int i) {
if (i == word.length) return true;
if (y<0 || x<0 || y == board.length || x == board[y].length) return false;
if (board[y][x] != word[i]) return false;
board[y][x] ^= 256;
boolean exist = exist(board, y, x+1, word, i+1)
|| exist(board, y, x-1, word, i+1)
|| exist(board, y+1, x, word, i+1)
|| exist(board, y-1, x, word, i+1);
board[y][x] ^= 256;
return exist;
}
The binary value for 256 is 100000000. Now we have ascii chars upto 255 numbers so their binary value is between - [0000可以0000 - 11111111] (0 - 255).
Now if you do XOR(^) operation between these ascii chars and 256 it will convert all the range above 256 number. Java has 16 bits for char type. So this is possible. And now none of out string chars will match any of these masked chars because one is under 0-255 other is above 256 range.
可以用二维数组表示移动方向
public class Solution {
public boolean exist(char[][] board, String word) {
char[] wordArray = word.toCharArray();
int[][] dirs = new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; for(int i = 0; i < board.length; i++) {
for(int j = 0; j < board[0].length; j++) {
if(dfs(board, dirs, i, j, wordArray, 0)) return true;
}
}
return false;
} public boolean dfs(char[][] board, int[][] dirs, int i, int j, char[] word, int start) {
if(start == word.length) return true;
if(i < 0 || j < 0 || i == board.length || j == board[0].length) return false;
if(board[i][j] == '#' || board[i][j] != word[start]) return false; boolean res = false;
char c = board[i][j];
board[i][j] = '#'; // use '#' to represent this cell is visited for(int[] dir: dirs) {
int newRow = i + dir[0], newCol = j + dir[1];
res |= dfs(board, dirs, newRow, newCol, word, start + 1);
if(res) return true; // if successfully find the word, return immediately
} board[i][j] = c; // backtracking
return false;
}
}
DFS leetcode的更多相关文章
- leetcode 39 dfs leetcode 40 dfs
leetcode 39 先排序,然后dfs 注意先整全局变量可以减少空间利用 class Solution { vector<vector<int>>ret; vector&l ...
- DFS - leetcode [深度优先遍历]
最短路径=>BFS 所有路径=>DFS 126. Word Ladder II BFS+DFS: BFS找出下一个有效的word进队 并记录step 更新两个变量:unordered ...
- (二叉树 递归 DFS) leetcode 100. Same Tree
Given two binary trees, write a function to check if they are the same or not. Two binary trees are ...
- (二叉树 BFS DFS) leetcode 104. Maximum Depth of Binary Tree
Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the long ...
- (二叉树 BFS DFS) leetcode 111. Minimum Depth of Binary Tree
Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the shor ...
- (BFS/DFS) leetcode 200. Number of Islands
Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surro ...
- 回溯法和DFS leetcode Combination Sum
代码: 个人浅薄的认为DFS就是回溯法中的一种,一般想到用DFS我们脑中一般都有一颗解法树,然后去按照深度优先搜索去寻找解.而分支界限法则不算是回溯,无论其是采用队列形式的还是优先队列形式的分支界限法 ...
- [LeetCode] questions conclustion_BFS, DFS
BFS, DFS 的题目总结. Directed graph: Directed Graph Loop detection and if not have, path to print all pat ...
- [LeetCode] 系统刷题4_Binary Tree & Divide and Conquer
参考[LeetCode] questions conlusion_InOrder, PreOrder, PostOrder traversal 可以对binary tree进行遍历. 此处说明Divi ...
随机推荐
- 一 web爬虫,requests请求
requests请求,就是用python的requests模块模拟浏览器请求,返回html源码 模拟浏览器请求有两种,一种是不需要用户登录或者验证的请求,一种是需要用户登录或者验证的请求 一.不需要用 ...
- idea结合git使用三
1.将本地代码提交到码云上面的步骤 2.先提交到本地Git的仓库,通过commit files 3.然后vcs----->git---->push,将本地仓库代码,推送到码云公司项目mas ...
- [转载]JAVA获取word表格中数据的方案
上一个项目的开发中需要实现从word中读取表格数据的功能,在JAVA社区搜索了很多资料,终于找到了两个相对最佳的方案,因为也得到了不少网友们的帮助,所以不敢独自享用,在此做一个分享. 两个方案分别是: ...
- Project Euler 126 - Cuboid layers
这题先是推公式… 狂用不完全归纳+二次回归,最后推出这么一个奇怪的公式 \[f(t,x,y,z)=4(t-1)(x+y+z+t-2)+2(xy+yz+xz)\] 表示长宽高为\(x\).\(y\).\ ...
- React 实现 Table 的思考
琼玖 1 年前 (写的零零散散, 包括github不怎么样) Table 是最常用展示数据的方式之一,可是一个产品中往往很多非常类似的 Table, 但是我们碰到的情况往往是 Table A 要排序, ...
- Git介绍及基本操作
Git基本概念 在Git中,我们将需要进行版本控制的文件目录叫做一个仓库(repository),每个仓库可以简单理解成一个目录,这个目录里面的所有文件都通过Git来实现版本管理,Git都能跟踪并记录 ...
- [EMWIN]关于 GUI_GetPixelIndex 使用的问题
在模拟器上和st单片机上使用以下代码: GUI_COLOR color0,color1; color0 = GUI_GetPixelIndex(rect.x1+1, rect.y0);color1 = ...
- 解决 Laravel/Lumen 出现 "Please provide a valid cache path" 问题
解决 Laravel/Lumen 出现 "Please provide a valid cache path" 问题 解决 Laravel/Lumen 出现 "Pleas ...
- 关于for循环中是否需要缓存length值的个人总结
在JS性能优化中,有一个常见的小优化,即 // 不缓存 for (var i = 0; i < arr.length; i++) { ... } // 缓存 var len = arr.leng ...
- rhel7+apache+c cgi+动态域名实现web访问
1. 申请动态域名/安装no-ip客户端 https://blog.csdn.net/lee244868149/article/details/44095835 2. yum安装httpd 两种方法安 ...