【剑指offer】搜索与回溯算法(6.13-6.14)

1、矩阵中的路径

在这里插入图片描述

class Solution {
    public boolean exist(char[][] board, String word) {
        char[] words = word.toCharArray();
        for(int i = 0; i < board.length; i++) {
            for(int j = 0; j < board[0].length; j++) {
                if(dfs(board, words, i, j, 0)) return true;
            }
        }
        return false;
    }
    boolean dfs(char[][] board, char[] word, int i, int j, int k) {
        if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k]) return false;
        if(k == word.length - 1) return true;
        board[i][j] = '\0';
        boolean res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) || 
                      dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i , j - 1, k + 1);
        board[i][j] = word[k];
        return res;
    }
}


作者:Krahets
链接:https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/58d5vh/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2、机器人的运动范围

这种在矩阵中遍历的题目,不同的地方就是递归退出的条件以及返回值。

class Solution {
    public int movingCount(int m, int n, int k) {
        int area = 0;
        boolean[][] visited = new boolean[m][n];
        return dfs(0,0,m,n,k,visited);
    }
    private int dfs(int i,int j,int m,int n,int k,boolean[][] visited){
        //递归退出条件
        if(i < 0 || i >= m || j < 0 || j >= n || (i%10)+(i/10)+(j%10)+(j/10) > k || visited[i][j]){
            return 0;
        }
        //遍历过的地方做标记
        visited[i][j] = true;
        int n1 = dfs(i-1,j,m,n,k,visited);
        int n2 = dfs(i+1,j,m,n,k,visited);
        int n3 = dfs(i,j-1,m,n,k,visited);
        int n4 = dfs(i,j+1,m,n,k,visited); 
        return n1+n2+n3+n4+1;
    }
}

3、树的子结构

输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)
B是A的子结构, 即 A中有出现和B相同的结构和节点值。

class Solution {
    public boolean isSubStructure(TreeNode A, TreeNode B) {
        if(A == null || B == null){return false;}
        return isSame(A,B) || isSubStructure(A.left,B) || isSubStructure(A.right,B);
    }
    public boolean isSame(TreeNode A,TreeNode B){
        //好像题意并不需要B和A的子结构完全一样
        //注意!!这里B==null的判断一定要放在前面!!
        if(B == null){return true;}
        if(A == null){return false;}        
        return isSame(A.left,B.left) && isSame(A.right,B.right) && (A.val == B.val);
    }
}

class Solution {
    public int maximumRemovals(String s, String p, int[] removable) {
        // List<Character> s1 = s.toCharArray().chars().mapToObj(c->(char) c).collect(Collectors.toList());
        if(s.length() == 0 || s.length() < p){return 0;}
        if(removable.length == 0){return subSeq(list,p,)}
        char[] ch = s.toCharArray();
        List<Character> list = new ArrayList<>();
        for(int i = 0;i < ch.length;i++){
            list.add(ch[i]);
        }
        int i = 0;
        for(;i < removable.length;i++){
            if(!subSeq(list.remove(removable[i]),p,start)){
                break;
            }
        }
        return i;
    }
    private boolean subSeq(List<Character> list,String p){
        if(list.size() < p){return false;}
        for(int i = start;i < p.length();i++){
            int index = list.indexOf(p.charAt(i));
            if(index == -1){
                return false;
            }else{
                subSeq(list.subList(index+1,list.size()),p.substring(start+1,p.length));
            }
        }
        return true;
    }
}

4、二叉树的镜像

输出给定二叉树的镜像

class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        if(root == null){return root;}
        if(root.left == null && root.right == null){return root;}
        swap(root);
        return root;
    }
    private void swap(TreeNode root){
        if(root == null){return;}
        TreeNode node = root.left;
        root.left = root.right;
        root.right = node;
        swap(root.left);
        swap(root.right);
    }
}
class Solution {
    public TreeNode mirrorTree(TreeNode root) {
        if(root == null) return null;
        TreeNode tmp = root.left;
        root.left = mirrorTree(root.right);
        root.right = mirrorTree(tmp);
        return root;
    }
}

5、对称的二叉树

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if(root == null){return true;}
        return judge(root.left,root.right);
    }
    private boolean judge(TreeNode A,TreeNode B){
        if(A == null && B == null){return true;}
        if(A == null || B == null){return false;}
        return judge(A.left,B.right) && judge(A.right,B.left) && A.val == B.val;
    }
}

6、 从上到下打印二叉树

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public int[] levelOrder(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        if(root == null){return new int[0];}
        Queue<TreeNode> q = new LinkedList<>();
        q.add(root);
        while(!q.isEmpty()){
            int size = q.size();
            for(int i = 0;i < size;i++){
                TreeNode node = q.poll();
                list.add(node.val);
                if(node.left!=null){
                    q.add(node.left);
                }
                if(node.right!=null){
                    q.add(node.right);
                }
            }
        }
        return list.stream().mapToInt(Integer::intValue).toArray();
    }
}

7、从上到下打印二叉树 II

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if(root == null){return res;}
        Queue<TreeNode> q = new LinkedList<>();
        q.add(root);
        while(!q.isEmpty()){
            int size = q.size();
            List<Integer> tmp = new ArrayList<>();
            //注意:循环这里第二个条件不能用q.size(),因为将左右节点加进去之后,q的大小发生了变化
            for(int i = 0;i < size;i++){
                TreeNode node = q.poll();
                tmp.add(node.val);
                if(node.left != null){
                    q.add(node.left);
                }
                if(node.right !=null){
                    q.add(node.right);
                }
            }
            res.add(tmp);
        }
        return res;
    }
}

8、从上到下打印二叉树 III

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        boolean flag = true;//true代表向右,false代表向左
        List<List<Integer>> res = new ArrayList<>();
        if(root == null){return res;}
        Queue<TreeNode> q = new LinkedList<>();
        q.add(root);
        while(!q.isEmpty()){
            int size = q.size();
            List<Integer> tmp = new ArrayList<>();
            for(int i = 0;i < size;i++){
                TreeNode node = q.poll();
                tmp.add(node.val);
                if(node.left !=null){
                    q.add(node.left);
                }
                if(node.right !=null){
                    q.add(node.right);
                }
            }
            if(flag){
                res.add(tmp);
                flag = false;
            }else{
                Collections.reverse(tmp);
                res.add(tmp);
                flag = true;
            }
        }
        return res;
    }
}

9、二叉树中和为某一值的路径

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public List<List<Integer>> pathSum(TreeNode root, int target) {
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> tmp = new ArrayList<>();
        if(root == null){return res;}
        dfs(root,target,res,tmp);
        return res;
    }
    private void dfs(TreeNode root,int target,List<List<Integer>> res,List<Integer> tmp){
        //必须走到叶子节点
        if(root == null){return;}
        tmp.add(root.val);
        target -= root.val;
        if(root.left == null && root.right == null && target == 0){
            res.add(new ArrayList(tmp));
        }
        dfs(root.left,target,res,tmp);
        dfs(root.right,target,res,tmp);
        tmp.remove(tmp.size()-1);
    }
}

——————————————————————————————————————————————6.14

10、二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。

11、序列化二叉树

和层序遍历不同的是,这里的节点假如为空,也要加入序列中

public class Codec {

    // Encodes a tree to a single string.
    public String serialize(TreeNode root) {
        if(root == null){return "[]";}
        StringBuilder res = new StringBuilder("[");
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        while(!queue.isEmpty()){
            TreeNode node = queue.poll();
            if(node!=null){
                res.append(node.val+",");
                queue.add(node.left);
                queue.add(node.right);
            }else{
                res.append("null,");
            }
        }
        //把最末尾的逗号去掉
        res.deleteCharAt(res.length()-1);
        res.append("]");
       // System.out.println(res.toString());
        return res.toString();
    }

    // Decodes your encoded data to tree.
    public TreeNode deserialize(String data) {
        if(data.equals("[]")){return null;}
        //首先得将节点值剥离
        String[] nodeVal = data.substring(1,data.length()-1).split(",");//字符串首尾都是括号
        //建立根节点
        TreeNode root = new TreeNode(Integer.parseInt(nodeVal[0]));
        Queue<TreeNode> q = new LinkedList<>();
        q.add(root);
        int i = 1;//从第二个数组值开始构建根节点的左右子树
        while(!q.isEmpty()){
            TreeNode node = q.poll();
            if(!nodeVal[i].equals("null")){
                node.left = new TreeNode(Integer.parseInt(nodeVal[i]));
                q.add(node.left);
            }
            i++;
            if(!nodeVal[i].equals("null")){
                node.right = new TreeNode(Integer.parseInt(nodeVal[i]));
                q.add(node.right);
            }
            i++;
        }
        return root;
    }
}

12、字符串的排列

全排列

class Solution{
    StringBuilder sb = new StringBuilder();
    public String[] permutation(String s) {
        if(s.length() == 0){return new String[0];}
        List<String> res = new ArrayList<>();
        boolean[] used = new boolean[s.length()];
        char[] str = s.toCharArray();
        Arrays.sort(str);
        dfs(str,used,res,sb);
        String[] st =new String[res.size()];
        for(int i = 0;i < res.size();i++){
            st[i] = res.get(i);
        }
        return st;
    }
    private void dfs(char[] str,boolean[] used,List<String> res,StringBuilder sb){
        //递归出口
        if(sb.length() == str.length){
            res.add(sb.toString());
            return;
        }
        for(int i= 0;i < str.length;i++){
            if(!used[i]){
                if(i > 0 && str[i] == str[i-1] && !used[i-1]){
                    continue;
                }else{
                    sb.append(str[i]);
                    used[i] = true;
                    dfs(str,used,res,sb);
                    used[i] = false;
                    sb.deleteCharAt(sb.length()-1);
                }               
            }
        }
    }
}

13、二叉搜索树的第K大节点

倒着中序遍历——右中左

class Solution {
    public int kthLargest(TreeNode root, int k) {
        List<Integer> res = new ArrayList<>();
        inOrder(root,k,res);
        return res.get(k-1);
    }
    private void inOrder(TreeNode root,int k,List<Integer> res){
        if(root == null){return;}
        inOrder(root.right,k,res);
        res.add(root.val);
        if(res.size() == k){return;}
        inOrder(root.left,k,res);
    }
}

14、二叉树的深度

class Solution {
    public int maxDepth(TreeNode root) {
        if(root == null){return 0;}
        int left = maxDepth(root.left);
        int right = maxDepth(root.right);
        return Math.max(left,right)+1;
    }
}

15、平衡二叉树

递归检查二叉树的每个节点的左右子树差即可
在这里插入图片描述

class Solution {
    public boolean isBalanced(TreeNode root) {
        if(root == null){return true;}
        //该节点的左右子树最大深度差
        if(Math.abs(judgeNode(root.left) - judgeNode(root.right)) > 1){
            return false;
        }
        //递归遍历左右子树的每个节点
        return isBalanced(root.left) && isBalanced(root.right);
    }
    private int judgeNode(TreeNode root){
        if(root == null){return 0;}
        int left = judgeNode(root.left);
        int right = judgeNode(root.right);
        return Math.max(left,right)+1;
    }

16、求1 + 2 + … + n

求 1+2+…+n ,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

在这里插入图片描述
在这里插入图片描述

class Solution{
	int res = 0;
	public int sumNums(int n) {
		boolean x = n>1&& sumNums(n-1)>0;
		res+=n;
		return res;
	}
}
//动态规划
class Solution {
    public int sumNums(int n) {
        int dp[] = new int[n+1];
        if(n == 0 || n == 1){return n;}
        dp[1] = 1;
        for(int i = 2;i < n+1;i++){
            dp[i] = dp[i-1]+i;
        }
        return dp[n];
    }
}

参考链接:https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/9h1gyt/

17、I. 二叉搜索树的最近公共祖先

左右子树递归:
假如都在左子树,那么先找到谁谁就是祖先;
假如都在右子树,那么先找到谁谁就是祖先;
假如一个在左子树,一个在右子树,那么公共祖先为根节点。

注意:可以利用二叉搜索树的值大小特性

//递归解法
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null){return null;}
        if(root == p || root == q){return root;}
        if(root.val < p.val && root.val < q.val) // p,q 都在 root 的右子树中
            root = lowestCommonAncestor(root.right,p,q); // 遍历至右子节点
        else if(root.val > p.val && root.val > q.val) // p,q 都在 root 的左子树中
            root = lowestCommonAncestor(root.left,p,q); // 遍历至左子节点
        return root;
    }
}
//迭代解法
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        while(root != null) {
            if(root.val < p.val && root.val < q.val) // p,q 都在 root 的右子树中
                root = root.right; // 遍历至右子节点
            else if(root.val > p.val && root.val > q.val) // p,q 都在 root 的左子树中
                root = root.left; // 遍历至左子节点
            else break;
        }
        return root;
    }
}


作者:Krahets
链接:https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/5793vc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

18、二叉树的最近公共祖先

注意:这个题是二叉树,不是二叉搜索树

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || root == p || root == q){return root;}
        TreeNode left = lowestCommonAncestor(root.left,p,q);
        TreeNode right = lowestCommonAncestor(root.right,p,q);
        //两者都不为空
        if(left != null && right!=null){
            return root;
        }
        //两者都为空
        if(left == null && right == null){
            return null;
        }
        return left == null?right:left;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值