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 ...
随机推荐
- iOS-证书真机调试
开发者账号分类 个人的 99$ 申请简单,付钱就行,688人民币 企业的 99$ 申请复杂,需要“邓白氏”认证,可以确认企业是合法有效的 可以管理团队开发 商业的 299$ 也需要邓白氏 ...
- ionic2——开发利器之Visual Studio Code 常用插件整理
1.VsCode官方插件地址: http://code.visualstudio.com/docs 2.使用方法,可以在官网中搜索需要的插件或者在VsCode的“”扩展“”中搜索需要的插件 添加方法使 ...
- .html() .text() .val() 的区别
.html()用为读取和修改元素的HTML标签(包括其Html标签) .text()用来读取或修改元素的纯文本内容 (包括其后代元素) .val()用来读取或修改表单元素的value值.(只能用于表单 ...
- shell编程学习1
1.shell是操作系统的终端命令行 (1)shell可以理解为软件系统提供给用户操作的命令行界面,可以说它是人机交互的一种方式. (2)我们可以使用shell和操作系统.uboot等软件系统进 ...
- eclipse 不能启动虚拟机
在eclipse文件下有个eclipse.ini文件打开它.现在如果没有-vm 这个参数那么就在最后新起一行写上 -vm+空格+参数 参数是你安装的jdk目录比如我的 -vm d:/java/jdk1 ...
- android线程 Handler Message Queue AsyncTask线程模型 线程交互 + 修改Button样式 示例 最终easy整合版
首先原谅我把文章的标题写的这么长.其实我还嫌弃它短了因为 写不下去了所以我就不写了.因为我实在不知道该怎么定义这篇文章的标题或许应该叫 "乱谈"比较合适. 这样可能还体现了 ...
- Skynet服务器框架(八) 任务和消息调度机制
引言: 在我看来,消息和任务调度应该是skynet的核心,整个skynet框架的核心其实就是一个消息管理系统.在skynet中可以把每个功能都当做一个服务,整个skynet工程在执行过程中会创建很多个 ...
- Android开发技巧——写一个StepView
在我们的应用开发中,有些业务流程会涉及到多个步骤,或者是多个状态的转化,因此,会需要有相关的设计来展示该业务流程.比如<停车王>应用里的添加车牌的步骤. 通常,我们会把这类控件称为&quo ...
- Mac上安装Jenkins持续部署初体验
1.首先去官网下载安装包 https://jenkins.io/doc/book/installing/ 安装完成后,很不幸,无法访问他的默认站点 查了一堆资料,有的说环境变量没有配置,有的说没有执行 ...
- Go语言使用匿名结构体解析JSON数据
手机拥有屏幕.电池.指纹识别等信息,将这些信息填充为 JSON 格式的数据.如果需要选择性地分离 JSON 中的数据则较为麻烦.Go 语言中的匿名结构体可以方便地完成这个操作. 首先给出完整的代码,然 ...