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内容也会被删除

扫描二维码关注公众号,回复: 1655272 查看本文章

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"机场出发,按照字典序从小到达取与其连接的地点,从下一个地点再递归的搜索,直到没有和某地点相连的机票的了.我们就到达了最底层,然后往上返回路径即可.

101. Symmetric Tree

判断一颗树是不是沿中线左右对称

     

    对称            不对称

非递归:也可以用两个队列分别存两边的。

https://leetcode.com/problems/symmetric-tree/discuss/33089/My-C++-Accepted-code-in-16ms-with-iteration-solution

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

猜你喜欢

转载自www.cnblogs.com/34fj/p/9118679.html